写在这个方便的记号中,这对我来说似乎很清楚。但我似乎无法使用>>=
来解决脱糖版本的工作问题。有人可以用扩展的表示法重写这些吗?
未嵌套
stack1 :: StateT Int Identity ( Int, Int )
stack1 = do
a <- get
put ( a + 1 )
b <- get
return ( a, b )
runstack1 :: ( Int, Int )
runstack1 = evalState stack1 11
嵌套
stack3 :: StateT Int ( StateT String ( StateT String Identity ) ) ( Int, String, String )
stack3 = do
modify (+10)
lift $ modify ( ++ " world" )
lift . lift $ modify ( ++ " word" )
a <- get
b <- lift get
c <- lift . lift $ get
return ( a, b, c )
runStack3 :: ( Int, String, String )
runStack3 = runIdentity $ evalStateT ( evalStateT ( evalStateT runStack3 1 ) "hello" ) "harro"
此外,通过比较runStack1和runStack3的签名,我可以看到为什么需要runIdentity
,但有人可以解释为什么会这样,因为stack1和stack3都包装了Identity构造函数?
答案 0 :(得分:3)
嵌套示例的Desugared版本:
stack4 :: StateT Int ( StateT String ( StateT String Identity ) ) ( Int, String, String )
stack4 = modify (+10) >>= \_ ->
(lift $ modify ( ++ " world" )) >>= \_ ->
(lift . lift $ modify ( ++ " word" )) >>= \_ ->
get >>= \a ->
lift get >>= \b ->
(lift . lift $ get) >>= \c ->
return (a,b,c)
以应用方式:
import Control.Applicative
stack5 :: StateT Int ( StateT String ( StateT String Identity ) ) ( Int, String, String )
stack5 = modify (+10) *>
(lift $ modify ( ++ " world" )) *>
(lift . lift $ modify ( ++ " word" )) *>
((,,) <$> get <*> lift get <*> (lift . lift $ get))
此外,Lambdabot可以执行自动脱臼,请参阅this question。
至于runIdentity
的需要,对此并不神秘。您必须打开monad堆栈的每一层以获取内部值,并且Identity
恰好位于堆栈中。现在,State
monad可以用StateT
和Identity
来实现,但在这种情况下,用户会看到一个隐藏内部机制的“统一视图”。如果您在runState
包中查看transformers
的源代码,则会看到它在内部调用runIdentity
。