2012-01-07 89 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想象成一个硬盘的大盘,存储在不同位置的值以及停放在特定位置的头部。