哈斯克尔:试图去除简单的国家monad得到和放弃

为了研究State monad的细节,我试图创建一个简单的状态monad函数的完整desugared版本,完成了
How does ‘get’ actually /get/ the initial state in Haskell?开始的思想,在J Cooper的答案中.

示例状态monad函数简单地交换状态和输入值,因此(概念上)如果输入是(v,s)则输出是(s,v).我展示了三种翻译,首先从do notation到desugared>> =和>>,然后将这些运算符置于功能位置,最后尝试替换它们并获取/放置它们的定义.

‘do’版本和前两个翻译有效,但最终翻译没有.问题:

>加载模块后,GHCi报告z1不在范围内.
>我还没弄清楚如何表示省略在>>中传递的参数翻译.

这些应该如何解决?

FWIW,当前的Haskell平台(GHC 7.4.2).

谢谢!

-- simpleswap

import Control.Monad.State

-- =============================================
-- 'Do' version
simpleswap1 :: String -> State String String
simpleswap1 inp = do
    z1 <- get
    put inp
    return z1

-- =============================================
-- Desugared to >>= and >>
simpleswap2 :: String -> State String String
simpleswap2 inp = 
    get >>= 
    \z1 -> put inp >>
    return z1 

-- =============================================
-- >>= and >> changed to function position
simpleswap3 :: String -> State String String
simpleswap3 inp = 
    (>>=) get 
    (\z1 -> (>>) (put inp)  (return z1) )


-- =============================================
-- Attempt to translate >>=, >>, get and put

simpleswap4 :: String -> State String String
simpleswap4 inp = 
    state $\s1 -> 
        -- (>>=) 
        let (a2, s2) = runState ( {- get -}  state $\sg -> (sg,sg) ) s1
        in  runState (rhs1 a2) s2
        where 
            rhs1 a2 = \z1 -> 
            -- (>>)
                state $\s3 -> 
                    let (a4, s4) = runState ( {- put inp -}  state $\_ -> (inp, ()) ) s3
                    in runState (rhs2 a4) s4
                    where
                        rhs2 a4 = return z1

-- =============================================
main = do
    putStrLn "version 1004"
    let v = "vvv"
    let s  = "sss"
    putStrLn ("Before val: " ++ v ++ "  state: " ++ s)    
    let (v2, s2) = runState (simpleswap4 v) s
    putStrLn ("After val: " ++ v2 ++ "  state: " ++ s2)

-- =============================================

最佳答案 simpleswap4中有一些小错误.这是一个更正版本:

simpleswap4 :: String -> State String String
simpleswap4 inp = 
    state $\s1 -> 
        -- (>>=) 
        let (z1, s2) = runState ( {- get -}  state $\sg -> (sg,sg) ) s1
        in  runState (rhs1 z1) s2
        where 
            rhs1 z1 = 
            -- (>>)
                state $\s3 -> 
                    let (_, s4) = runState ( {- put inp -}  state $\_ -> ((), inp) ) s3
                    in runState rhs2 s4
                    where
                        rhs2 = return z1

我已将a2重命名为z1(第5行和第6行).这并没有改变语义,但强调了desugared get调用返回的对的第一个组件实际上是在以前版本的simpleswap中绑定到z1的结果.

rhs1的类型应该是String – >状态字串串.在您的版本中,它会获得一个额外的lambda绑定变量.目前还不清楚你的版本中a2和z1之间应该有什么区别.删除lambda(在第8行中)还具有修复范围问题的优势.您在嵌套的where子句中使用z1,但where只能看到绑定在它所附加的声明左侧的变量.

在第11行,我用_替换了a4.这是为了强调(>>)确实丢弃了第一个动作的结果.因此,rhs2也没有参数化.

点赞