【问题标题】:How to structure complex "state updating functions" in Clojure?如何在 Clojure 中构建复杂的“状态更新函数”?
【发布时间】:2014-07-14 21:21:40
【问题描述】:

我有一个表示为地图的游戏状态和一些更新每个游戏“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)

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

一个有效的方法是使用一个被重置的本地原子!对于更新函数中的每一行。但这不可能是它应该做的?!

【问题讨论】:

    标签: design-patterns clojure functional-programming


    【解决方案1】:

    我建议将每个步骤提取到一个命名良好的函数中,以便您可以使用 ->。伪代码:

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

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

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

    还可以查看cond->,看看你如何将 -> 与一些条件混合。例如,您的 cond 可能如下所示:

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

    【讨论】:

    • 针对逻辑块的命名函数和 synthread 库的组合看起来是一个不错的解决方案。它的宏类似于另一个答案中描述的“mabey”宏(还有更多)。
    【解决方案2】:

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

    (-> 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

    【讨论】:

    • 你应该看看cond->,我相信它会很好地取代maybe
    • @omiel cond-> 绝对是一个选择,所以我相应地编辑了我的答案。但是,如果您的大多数条件都是 true 并且如果您想在条件中使用当前值则不起作用。我编辑了我的答案以使 maybe 宏真正有用 - 在它只是移动匿名函数创建问题而不是解决它之前。
    • 您误会了:我建议您将 cond-> 表单嵌套在 -> 中,而不是您只使用 cond->
    • @omiel 正确,尽管在某些情况下可能更强大。添加了一个额外的示例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-22
    • 1970-01-01
    相关资源
    最近更新 更多