2012-01-07 91 views

回答

30

如果您看一下StoreT itself的定義會容易得多。

你可以把它想象成一個更大結構中的「地方」。例如,lens只是a -> Store b a;您將得到b字段的值,並且可以使用函數b -> a將新值重新放入更大的上下文中。

考慮在其簡化的非變壓器形式:

data Store s a = Store (s -> a) s 

instance Functor (Store s) where 
    fmap f (Store g s) = Store (f . g) s 

instance Extend (Store s) where 
    duplicate (Store f s) = Store (Store f) s 

instance Comonad (Store s) where 
    extract (Store f s) = f s 

duplicate改變s -> as -> Store s a剛更換後的值返回「更新」的地方,extract恢復原始一個將該值放回到較大的結構中。

至於它關係到國家的話,你可以看看這樣的:

type State s a = s -> (a, s) 
type Store s a = (s -> a, s) 
+15

爲了擴大國家和商店之間的聯繫,所有單子都來自伴隨函子的組合。衆所周知,函子'(r - > _)'(又名Reader)和'(_,r)'(翻轉過來也可以,但不適合Haskell中通常的狀態表示,並且不能成爲Haskell中的Functor實例)是伴隨的,如果你以單向方式('s - >(_,s)')構造它們,你將得到一個monad,如果你用另一種方式構造它們('(s - > _ s)')你會得到一個comonad。 – copumpkin 2012-01-08 04:24:33

+0

@copumpkin:它不能是Functor的'(_,r)',不是嗎? '(r,_)'只是'實例Functor((,)r)'。 – ehird 2012-01-08 06:07:15

+0

是的,對不起,我錯誤地編輯了那個括號內的評論:) – copumpkin 2012-01-12 03:57:29

33

鑑於專賣店的如下定義,

data Store s a = Store { peek :: s -> a, pos :: s } 

我喜歡把一個Store作爲一個大型倉庫填充了a類型的值。 a類型的每個值都被分割到由s類型的索引值標記的位置。最後有一輛叉車停在pos的位置。叉車可用於extract價值a從商店通過拉出值從它停放的地方。您可以使用seek將叉車移動到新的絕對位置,或使用seeks將叉車移動到新的相對位置。要更新商店的所有值,請使用fmap。最後extend f類似於fmap,除了替代f :: a -> a'我們有f :: Store s a -> a'它允許更新函數不僅可以訪問正在更新的值,還可以訪問該值的位置並訪問存儲中其他所有值的值。換句話說,extend使用該值加上其周圍的上下文來執行更新。

一個更加計算機的比喻是將Store想象成一個硬盤的大盤,存儲在不同位置的值以及停放在特定位置的頭部。