如何在Clojure中更好地迭代状态(monad?)

时间:2012-04-26 16:55:00

标签: clojure functional-programming state monads

我刚写了这段代码:

(defn parameters [transform-factory state]
  (lazy-seq (let [[r1 state] (uniform state)
                  [r2 state] (uniform state)
                  [t state] (transform-factory state)]
              (cons [t [r1 r2]] (parameters transform-factory state)))))

(defn repeated-transform [mosaic n transform-factory state]
  (reduce transform-square mosaic
    (take n (parameters transform-factory state))))

parameters函数生成一个由state生成的惰性值序列,用于参数化某些事物的重复转换(在本例中为“马赛克”)。

在我看来,parameters显示了一个相当常见的模式,当你有一些必须随身携带的state时(在这种情况下生成随机值)。有这个名字吗?

有没有更好的方法来编写第一个函数?相关的问题通常可以用reduce来解决,reductions“携带”状态,但在这里我没有什么可以减少的。同样地,{{1}}似乎不合适。这对monad来说是个好例子吗? (从理论上看,我没有看到你如何定义一种方法将多个实例合并为一个,但也许这并没有改变实际应用 - 它看起来像monad解决其他地方的问题,一些国家需要随身携带)。

(ps我提到了随机数字,但我无法用在幕后使用可变状态的解决方案替换它 - 正如“普通”随机例程那样 - 出于与问题无关的原因)。

3 个答案:

答案 0 :(得分:4)

你当然可以看一下状态monad,看看它是否适合你。

使用monad的一般准则是:

  • 顺序执行(管道操作)
  • 可重复使用的模块化副作用处理(例如:错误处理/记录/ 状态)
  • 使用纯函数保持业务逻辑清洁

我觉得非常有用(对于Clojure)的monad上的一些资源是

Adam Smyczek: Monads简介(视频) http://www.youtube.com/watch?v=ObR3qi4Guys

和 吉姆杜伊: Clojure的Monads http://www.clojure.net/2012/02/02/Monads-in-Clojure/

答案 1 :(得分:3)

[回答自己,因为这是我迄今为止找到的最佳解决方案]

您可以将上述内容重写为功能上的折叠。所以函数成为数据,状态是“通过”,并且所使用的函数依次将每个函数应用于状态并累积结果。

我看不到一种优雅的方式来实现这一点 - 折叠的函数似乎是“新的”,你需要额外的样板来添加/分离状态和累加器 - 所以我将整个过程包装在一个名为fold-oversource is herean example of the function in use is here

答案 2 :(得分:3)

您应该检查的是->->>,即线程宏。

而不是像这样的代码:

(let [state (dosomething state)
      state (dosomethingelse state)
      state (dolastthing state)]
    state)

你可以写:

(-> state (dosomething) (dosomethingelse) (dolasttthing))

“线程”通过函数说明,最终返回它。

现在,您的代码并不完全遵循我所写的内容。我想象它可以遵循它的方式是你的函数采用并返回哈希映射。即(统一状态)可以返回{:state state-val :r1 r1-val}

然后你可以像这样重写你的代码:

(->> {:state state} (merge uniform) (merge uniform) (transform-factory))

好多了! :)