如何构建复杂的状态更新功能"在Clojure?

时间:2014-07-14 21:21:41

标签: design-patterns clojure functional-programming

我有一个游戏状态表示为地图和一些逻辑,可以在每个游戏中更新该状态' tic'。但我无法弄清楚如何以任何理智的方式构建更新功能。

这样构造函数的惯用模式是什么?

以下是我想要做的一些伪代码:

(defn tic [g] "Return an updated game"
  g1 = (update-in g [:day] inc)
  g2 = (if (some-cond) (some-update-func g1) g1)
  g3 = (update-in g2 [:fu] fu-update)
  ... many more ...
  g-last)

我不太关心中间状态,但使用 - >宏不起作用(因为有一些条件)。

有效的黑客正在使用重置的本地原子!对于每一行'在更新功能中。但这不可能是它应该如何完成的?!

2 个答案:

答案 0 :(得分:6)

我建议在一个名称很好的函数中提取每个步骤,这样就可以使用 - >。伪代码:

(defn tic [g]
    (-> g
        inc-day
        random-weather
        grow-trees
        ...))

对于任何条件逻辑,您可以执行类似于g2步骤中的操作。

也许你会发现synthread lib有用。我发现this video很有启发性。

同时查看cond->,看看你如何混合 - >与一些cond。例如,您的cond可能如下所示:

(cond-> g
        true (update-in [:day] inc)
        (some-cond) some-update-fund
        true (update-in [:fu] fu-update))

答案 1 :(得分:3)

如果对于条件步骤,您仍然可以使用->,将操作包装在匿名函数中。

(-> g0 
    ...
    (#(if (some-cond) (u %) %))
    ...)

如果你担心效率(你提到这是游戏),我建议你使用cond->或者创建自己的宏。 cond->要求对始终为线程的表达式重复true,这可能很乏味,具体取决于线程中的项目数。

这是一个可以与->结合使用的宏,可以避免过度创建匿名函数并避免cond->的重复性:

(defmacro maybe [val sym cond expr]
  `(let [~sym ~val] (if ~cond ~expr ~sym)))

可以像这样使用:

(-> g0
    ...
    (maybe gn (some-cond gn) (updater gn))
    ...)

如果您不需要在条件表达式中使用部分处理的值gn,则可以使用cond->代替maybe

(-> g0
    ...
    (cond-> (some-cond g0) updater)
    ...)

另一个例子:

(-> 10 (maybe gn (= gn 10) (* gn 100)))

评估为1000