在教程Learn You a Haskell - chapter 'for-a-few-monads-more', section 'The State monad'中,它列出了以下内容来定义State Monad:
newtype State s a = State { runState :: s -> (a,s) }
instance Monad (State s) where
return x = State $ \s -> (x,s)
(State h) >>= f = State $ \s -> let (a, newState) = h s
(State g) = f a
in g newState
只需回答一个简单的问题:\ s的输入是什么(因为状态h =一个接受状态并输出元组的函数(result,newState);暗示输入到\ s只会是那个功能)?欢迎举例
答案 0 :(得分:2)
您可以将State s a
的值视为一个计算,它取决于运行计算时提供的某些状态参数。你可以通过简单地展开包含的函数并调用它来实现这一点。例如
runState (return 1) "state"
=> (1, "state")
答案 1 :(得分:1)
你可以将return x
描述为“给我一个州,我会把你的状态和x给你”。然后,您可以将x >>= f1
视为“给我一个州,我会将其提交给x
;一旦它返回状态和值,我会将这些给予f
并传递f
给我的东西。“
这是与功能组成的类比:
f, g, h :: a -> a
j = f . g . h :: a -> a
j
是一个接受a
并返回a
的函数。在此过程中,该值首先被赋予h
,其输出转到g
,其输出转到f
,其输出将被返回。
查看返回State
值的函数的“组合”。
f', g', h' :: a -> State s a
j' a = return a >>= h' >>= g' >>= f'
将State
视为“隐藏”函数参数的一种方式。您可以像这样手动编写它们:
f'', g'', h'' :: a -> s -> (a, s)
-- We could make this point-free by leaving h curried, but this
-- is nicely consistent.
j'' a s = (uncurry f'') . (uncurry g'') . (uncurry h'') $ (a, s)
但是State
monad通过>>=
的实现有效地为您做到了这一点。
请注意,j'
仅采用初始值,而j''
采用初始值和作为初始状态。那是因为j'
采用该状态的函数仍然包含在State
值中;我们使用runState
来检索该函数,以便可以将初始状态提供给堆栈中的第一个函数。
(runState j') s0 -- parentheses optional, shown for emphasis