为了研究 State monad 的细节,我正在尝试为自己创建一个简单的 state monad 函数的完整脱糖版本,完成在“如何获取”实际上 /get/ Haskell 中的初始状态?,在 J Cooper 的回答中。
示例状态单子函数只是交换状态和输入值,因此(从概念上讲)如果输入是 (v, s),那么输出是 (s, v)。我展示了三种翻译,首先从 do 符号到脱糖的 >>= 和 >>,然后将这些运算符放在函数位置,最后尝试替换它们并使用它们的定义获取/放置。
'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)
-- =============================================