为了研究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也没有参数化.