我刚写了这段代码:
(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我提到了随机数字,但我无法用在幕后使用可变状态的解决方案替换它 - 正如“普通”随机例程那样 - 出于与问题无关的原因)。
答案 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-over
。 source is here和an 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))
好多了! :)