代码之家  ›  专栏  ›  技术社区  ›  mikera

这是一个明智的单子为可变的状态在Clojure?

  •  1
  • mikera  · 技术社区  · 14 年前

    我已经在clojure中尝试过monads,并提出了以下代码,其中一个单值/状态对由一个可变的clojure deftype对象表示。

    由于对象是可变的,一个优势似乎是您可以编写一元代码,而无需一直构造新的结果对象。

    不过,我对单子还很陌生,所以很想知道:

    • 这个结构有意义吗?
    • 它真的能像单子一样正常工作吗?

    代码如下:

    (defprotocol PStateStore 
      (set-store-state [ss v])
      (get-store-state [ss])
      (set-store-value [ss v])
      (get-store-value [ss]))
    
    (deftype StateStore [^{:unsynchronized-mutable true} value 
                         ^{:unsynchronized-mutable true} state]
      PStateStore 
          (get-store-state [ss] (.state ss))
          (get-store-value [ss] (.value ss))
          (set-store-state [ss v] (set! state v))
          (set-store-value [ss v] (set! value v))
    
       Object
         (toString [ss] (str "value=" (.value ss) ", state=" (.state ss))))
    
    (defn state-store [v s] (StateStore. v s))
    
    (defmonad MStoredState
      [m-result (fn [v] 
                  (fn [^StateStore ss] 
                      (do
                        (set-store-value ss v)
                        ss)))
       m-bind (fn [a f]
                (fn [^StateStore ss]
                  (do
                    (a ss)
                    ((f (get-store-value ss)) ss))))])
    
    ; Usage examples
    
    (def mb
      (domonad MStoredState
        [a (m-result 1)
         b (m-result 5)]
        (+ a b)))
    
    (def ssa (state-store 100 101))
    
    (mb ssa)
    
    ; => #<StateStore value=6, state=101>
    
    1 回复  |  直到 14 年前
        1
  •  3
  •   gasche    14 年前

    不,它不能作为monad正确工作,因为您使用可变状态。

    假设你有一个单值 m (一个值,带有一个状态),您称之为 StateStore . 您希望能够这样做:

    (let
       [a (incr-state m)
        b (decr-state m)]
      (if some-condition a b))
    

    我期望这个计算返回一元 根据 some-condition ,递增或递减。如果你使用可变状态,它将是 二者都 在计算此代码期间递增和递减。

    Monads的一个优点是, 代表 效果,它们表现为普通的纯的、不可变的值。你可以传递它们,复制它们(你可以扩展 let -一元值的定义,将其名称替换为每个使用站点的定义)。你唯一要小心的地方就是 使用效果 m-bind . 否则,在代码的不相关部分没有隐式链接效果,就像在通常的命令式编程中一样。这就是为什么在你想限制副作用的情况下,对monads的推理更容易、更舒适。

    编辑

    你可能听说过 一元定律 ,这是任何Monad实现都应该遵守的公式。然而,你在这里的问题并不是你违法,因为法律并没有讨论这个问题。事实上,单元定律通常用纯语言haskell来表述,因此不考虑副作用。

    如果你愿意的话,你可以把它当作第四条不成文的单子法则:好的单子应该受到尊重。 referential transparency