我正在“为哈萨克斯坦学到伟大的东西!”这本书中了解州立单子。由Miran Lipovaca撰写。 对于以下monad实例:
instance Monad (State s) where
return x = State $ \s -> (x,s)
(State h) >>= f = State $ \s -> let (a, newState) = h s
(Stage g) = f a
in g newState
我在理解>>=
函数的定义时遇到了麻烦。我不确定h
是有状态计算(即采用状态并返回具有更新状态的结果的函数)还是状态。我猜想它必须是有状态的计算,因为它已应用于lambda函数中的类型s
的状态以产生结果(a, newState)
。
但是根据状态s a的类型声明:
newtype State s a = State { runState :: s -> (a,s) }
状态的类型为s
,结果的类型为a
。因此,对于monad实例,s
中的instance Monad (State s) where
是状态类型还是实际上是有状态计算?任何见解都会受到赞赏。
答案 0 :(得分:7)
State
对象不存储状态。它存储“状态改变”。实际上,它存储了一个函数runState :: s -> (a, s)
。这里的s
是状态的类型,a
是状态的类型。
该函数因此将状态作为输入,并返回2元组(a, s)
。这里的第一项是“输出”,第二项是“新状态”。新状态可能与旧状态相同,但是新状态因此有机会更改状态(否则使用State
并不是很有用)。
我们可以将State
更改对象和状态更改对象(a -> State s b
)的“工厂”绑定到新的State
更改对象中。因此,我们构造了一个具有初始状态s0
的函数。我们首先将其运行到runState
对象的State
,然后检索一个2元组(a, s1)
。然后,我们可以使用此a
来构建State s b
对象,然后通过该s1
对象的runState
运行(改变的状态)State
。
因此,更详细的实现是:
instance Monad (State s) where
return x = State $ \s -> (x,s)
(State h) >>= f = State g
where g s0 = (b, s2) -- result of second runState
where (a, s1) = h s0 -- run through first runState
-- create second state with the output of the first
State f' = f a
(b, s2) = f' s1 -- run through second runState
请注意,这里我们实际上从未拥有状态值。我们只构造一个新的函数,该函数将在该状态值上工作。
从原理上讲,我们可以看到绑定操作符如下:
s0 \ / | | | | |||| |\_________ | ' | s1 v \ / a -----> | | | | |||| |\_______ | ' v s2 b
因此,这里的第一个runState
处于初始状态s0
,将返回一个a
和s1
。使用a
,我们构造了一个新的runState
,然后可以进一步处理状态s1
,并返回一个b
和新的状态s2
。