Design patterns Clojure中功能状态更新的模式/习惯用法

Design patterns Clojure中功能状态更新的模式/习惯用法,design-patterns,functional-programming,clojure,Design Patterns,Functional Programming,Clojure,我决定尝试在Clojure中编写一个模拟程序(作为概念证明),其中: 模拟的整个状态存储在一个不可变的数据结构中 状态更新表示为将状态映射到下一个状态的函数 这意味着我可以编写如下更新函数: (defn example-update-function [old-state] (let [state (atom old-state)] (swap! state some-other-update-function-1) (if (some-condition @state)

我决定尝试在Clojure中编写一个模拟程序(作为概念证明),其中:

  • 模拟的整个状态存储在一个不可变的数据结构中
  • 状态更新表示为将状态映射到下一个状态的函数
这意味着我可以编写如下更新函数:

(defn example-update-function [old-state]
  (let [state (atom old-state)]
    (swap! state some-other-update-function-1)
    (if (some-condition @state)
      (swap! state some-conditional-update-function))
    (swap! state some-other-update-function-2)
    (reset! state (some-function @state some-other-param))
    @state))
该方法似乎有效,但以下是我关注的两个原因:

  • 我不得不用一个可变原子来管理中间态。。。似乎不太实用
  • 代码看起来有点难看与所有的交换!s和@state到处都取消引用

有更好/更优雅的方法吗?

单子?每个人都对状态单子感到兴奋,我认为它是为这类事情而设计的。

这就是为什么发明了状态单子,以一种看似惯用的方式对状态修改模式进行编码,但在幕后使用共享不变的数据结构。通常会得到三个操作,两个核心,一个派生:

get :: m s   
  -- Return the state from the internals of the monad.

put :: s -> m ()  
  -- Replace the state inside the monad.

modify :: (s -> s) -> m ()   
  -- Maps an old state to a new state inside a state monad. The old state is thrown away.

因此,也许可以对这些原语进行编码,以使您的状态更容易。

您可以这样编写:

(defn change-when "If (test val) is truethy, returns (fun val), else returns val" [val test fun] (if (test val) (fun val) val)) (defn example-update-function [old-state] (-> old-state some-other-update-function-1 (change-when some-condition some-conditional-update-function) some-other-update-function-2 (some-function some-other-param) identity)) (定义在以下情况下更改) 如果(test val)为true,则返回(fun val),否则返回val [val test fun](如果(测试val)(VAN val)val)) (defn示例更新函数[旧状态] (->旧州 some-other-update-function-1 (当某些条件或某些条件更新函数发生变化时) some-other-update-function-2 (某些函数某些其他参数) 身份)
可能是单子之路的一半…

是什么触发了状态的改变?不清楚为什么要在这里改变
状态
原子,或者为什么要使用原子。你调用的函数是否以某种方式读取了它?@seh:是的,函数可能读取原子,并且需要状态的最新版本(即,不能仅仅依赖旧状态,因为在模拟中可能会产生顺序效果)@ponzao:可以是任何东西,但最常见的触发器是a)经过一段时间后,需要更新模拟或b)外部交互触发更改,例如用户更改一个模拟参数或直接修改模拟的某些部分