7

我刚刚写了这段代码:

(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似乎不适合。这是一个单子的好例子吗?(从理论上的观点来看,我看不到您如何定义将多个实例组合为一个的方法,但这可能不会改变实际应用-它确实看起来像是单子在其他地方解决的问题,其中某些状态需要随身携带)。

(ps我提到了随机数,但由于与问题无关的原因,我不能用在幕后使用可变状态的解决方案来替换它 - 正如“正常”随机例程所做的那样)。

4

3 回答 3

4

您当然可以查看 state monad,看看它是否适合您。

使用 monad 的一般准则是:

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

我发现(对于 Clojure)非常有用的一些关于 monad 的资源是

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

和 Jim Duey:Clojure 中的 Monads http://www.clojure.net/2012/02/02/Monads-in-Clojure/

于 2012-04-27T02:04:51.990 回答
3

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

您可以将以上内容重写为函数的折叠。所以函数变成了数据,状态是“通过”,使用的函数将每个函数依次应用到状态并累加结果。

我看不到一种优雅的方式来实现这一点——折叠的函数似乎是“新的”,你需要额外的样板来添加/分离状态和累加器——所以我将整个过程包装在一个名为fold-over. 源代码在这里使用的函数的例子在这里

于 2012-04-29T20:30:05.677 回答
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))

好看多了!:)

于 2012-05-02T22:10:13.110 回答