有人可以去除这个monad变换片段吗?

时间:2013-03-23 14:56:37

标签: haskell monad-transformers

写在这个方便的记号中,这对我来说似乎很清楚。但我似乎无法使用>>=来解决脱糖版本的工作问题。有人可以用扩展的表示法重写这些吗?

未嵌套

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构造函数?

1 个答案:

答案 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可以用StateTIdentity来实现,但在这种情况下,用户会看到一个隐藏内部机制的“统一视图”。如果您在runState包中查看transformers的源代码,则会看到它在内部调用runIdentity