我希望通过以下函数传递State monad:
e1 :: Int -> (Bool, Int)
e1 el
| el > 100 = (True, el)
| otherwise = (False, 0)
e2 :: Int -> (Bool, Int)
e2 el
| el > 200 = (True, el)
| otherwise = (False, 0)
e3 :: Int -> (Bool, Int)
e3 el
| el > 300 = (True, el)
| otherwise == (False, 0)
implementor :: State Bool Int
implementor = state e1 ...
main = do
print $ runState implementor 10
目前runState
传递State s a
(implementor
)和值(10),然后从e1
返回元组。
但是我想将这些操作绑定在一起,例如:
state e1 >>= e2 >>= e3
e1
会将其State Bool Int
传递给e2
,Int
会对el
(通过State Bool Int
)进行操作,然后将其传递给e3
} Int
再次对此传入状态的instance Monad (State s) where
return :: state $ \s -> (s, a)--this is returning a State which contains function (s -> (s, a))
m >>= k = state $ \s -> let (a, s') = runState m s --?
in runState (k a) s'
进行操作。
我发现Monad State的实例非常混乱,遵循this指南:
e1
我不明白这个bind实例在做什么以及如何使用它来绑定e2
,e3
和var in = ["0:3", "1:3", "4:5", "5:6", "6:8"]
?
答案 0 :(得分:5)
如果您在state :: (s -> (a, s)) -> State s a
上使用e1
,则最终会得到State Int Bool
:
state e1 :: State Int Bool
这是一种状态(在这种情况下为Int
)并且由于使用该状态而产生Bool
。因此,如果我们想要在有状态计算中相互使用e1
,e2
和e3
,我们可以将它们与do
一起使用 - 符号:
allThree :: State Int ()
allThree = do
firstBool <- state e1
secondBool <- state e2
thirdBool <- state e3
return thirdBool
但是,如果我们忽略前两个Bool
,我们可以删除绑定:
allThree :: State Int Bool
allThree = do
state e1
state e2
state e3
现在我们可以使用do
和>>
重写>>=
- 符号。我们最终得到了
allThree :: State Int Bool
allThree = state e1 >> state e2 >> state e3
至于如何运作,让我们来看看>>=
m >>= k = state $ \s -> let (a, s') = runState m s
in runState (k a)
而m >> k
是m >>= const k
。那么让我们来看看state e1 >> state 2
做了什么:
state e1 >> state e2
= state e1 >>= const (state e2)
= state $ \s -> let (a, s') = runState (state e1) s in runState (const (state e2) a) s'
-- simplify runState (state e1) s to e1 s
= state $ \s -> let (a, s') = e1 s in runState (const (state e2) a) s'
-- use "const"
= state $ \s -> let (a, s') = e1 s in runState (state e2) s'
-- again simplify runState (state e2) s' to e2 s'
= state $ \s -> let (a, s') = e1 s in e2 s'
因此,以下术语是相同的:
stateful s = runState (state e1 >> state e2) s -- use above to show that
stateless s = let (_, s') = e1 s
in e2 s'
现在,为什么我可以将更改runState (state f)
用于f
?因为State
的定义相当无聊:
-- simplified, modern versions use a more sophisticated approach!
newtype State s a = State { runState :: s -> (a, s) }
也就是说,State
个动作是一种状态,它会返回一个状态并返回一个新值。 state
函数非常简单:
state :: (s -> (a, s)) -> State s a
state = State
由于runState (State f)
是f
,runState (state f)
也是`f'。
因此,我们可以将Monad
实例写得有点不同:
instance Monad (State s) where
(State e1) >>= f = State e3
where
e3 s = let (a, s') = e s
(State e2) = f a
in e2 s'
请记住,>>=
期望一个函数可以获取某些内容并返回另一个操作,而>>
可以用于将操作链接到彼此之后。