为了研究State monad的细节,我试图创建一个简单的状态monad函数的完整desugared版本,完成在How does 'get' actually /get/ the initial state in Haskell?开始的思想,在J Cooper的答案中。
示例状态monad函数只是交换状态和输入值,因此(概念上)如果输入是(v,s)则输出是(s,v)。我展示了三种翻译,首先是从符号到desugared>> =和>>,然后将这些运算符置于功能位置,最后尝试替换它们并获取/放置它们的定义。
'do'版本和前两个翻译有效,但最终翻译没有。问题:
如何解决这些问题?
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)
-- =============================================
答案 0 :(得分:2)
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
调用返回的对的第一个组件实际上是在先前版本的z1
中绑定到simpleswap
的结果
rhs1
的类型应为String -> State String String
。在您的版本中,它会获得一个额外的lambda绑定变量。目前还不清楚a2
和z1
之间的差异应该在您的版本中。删除lambda(在第8行中)还具有修复范围问题的优势。您在嵌套的z1
- 子句中使用where
,但where
只能看到绑定在其附加的声明左侧的变量。
在第11行,我已将a4
替换为_
。这是为了强调(>>)
确实丢弃了第一个动作的结果。因此,rhs2
也未针对此结果进行参数化。