在 RWS monad 中解释 Teletype 免费 monad
Interpreting the Teletype free monad in the RWS monad
我目前正在学习免费的 monad,我正在尝试可能是最简单和最常见的例子 – Teletype
:
{-# LANGUAGE DeriveFunctor #-}
import Control.Monad.Free
data TeletypeF a = Put String a
| Get (String -> a)
deriving Functor
type Teletype = Free TeletypeF
许多教程在 IO
monad 中解释 Teletype
程序。例如:
-- Utilities
get = liftF $ Get id
put s = liftF $ Put s ()
-- Sample programs
echo :: Teletype ()
echo = do word <- get
if word == "" -- Ctrl-D
then return ()
else put word >> echo
hello :: Teletype ()
hello = do put "What is your name?"
name <- get
put "What is your age?"
age <- get
put ("Hello, " ++ name ++ "!")
put ("You are " ++ age ++ " years old!")
-- Interpret to IO
interpIO :: Teletype a -> IO a
interpIO = foldFree lift
where
lift (Put s a) = putStrLn s >> return a
lift (Get f) = getLine >>= return . f
我试图用不同的单子来解释它,即 RWS 单子。
这个想法是由 this assignment 的最后一个练习激发的。
我正在使用 RWS
数据类型从 Reader
部分获取输入并在 State
部分累积输出。
但是,不幸的是,我无法让它工作。到目前为止,这是我的尝试:
import Control.Monad.Trans.RWS.Lazy hiding (get, put)
type TeletypeRWS = RWS [String] () [String]
-- Interpret to TeletypeRWS
interpRWS :: Teletype a -> TeletypeRWS a
interpRWS = foldFree lift
where
lift (Put s a) = state (\t -> ((), t ++ [s])) >> return a
lift (Get f) = reader head >>= local tail . return . f -- This is wrong
mockConsole :: Teletype a -> [String] -> (a, [String])
mockConsole p inp = (a, s)
where
(a, s, _) = runRWS (interpRWS p) inp []
当运行 TeletypeRWS
"programs"时,环境中的第一个值不被移除:
*Main> mockConsole hello ["john", "18"]
((),["What is your name?","What is your age?","Hello, john!","You are john years old!"])
我对更新 Reader
有点不安,但我不知道还有什么方法可以访问列表中的下一个值。 TeletypeRWS
的类型是根据上面提到的练习选择的——所以我认为应该可以实现 interpRWS
.
我们不能使用foldFree
:它需要在continuation中是参数化的,所以我们不能在那里应用local
。相比之下,iterM
明确地给了我们实际的延拓而不是泛化,所以这会起作用。
interpRWS = iterM lift where
lift (Put s a) = modify (\t -> t ++ [s]) >> a
lift (Get f) = reader head >>= local tail . f
我目前正在学习免费的 monad,我正在尝试可能是最简单和最常见的例子 – Teletype
:
{-# LANGUAGE DeriveFunctor #-}
import Control.Monad.Free
data TeletypeF a = Put String a
| Get (String -> a)
deriving Functor
type Teletype = Free TeletypeF
许多教程在 IO
monad 中解释 Teletype
程序。例如:
-- Utilities
get = liftF $ Get id
put s = liftF $ Put s ()
-- Sample programs
echo :: Teletype ()
echo = do word <- get
if word == "" -- Ctrl-D
then return ()
else put word >> echo
hello :: Teletype ()
hello = do put "What is your name?"
name <- get
put "What is your age?"
age <- get
put ("Hello, " ++ name ++ "!")
put ("You are " ++ age ++ " years old!")
-- Interpret to IO
interpIO :: Teletype a -> IO a
interpIO = foldFree lift
where
lift (Put s a) = putStrLn s >> return a
lift (Get f) = getLine >>= return . f
我试图用不同的单子来解释它,即 RWS 单子。
这个想法是由 this assignment 的最后一个练习激发的。
我正在使用 RWS
数据类型从 Reader
部分获取输入并在 State
部分累积输出。
但是,不幸的是,我无法让它工作。到目前为止,这是我的尝试:
import Control.Monad.Trans.RWS.Lazy hiding (get, put)
type TeletypeRWS = RWS [String] () [String]
-- Interpret to TeletypeRWS
interpRWS :: Teletype a -> TeletypeRWS a
interpRWS = foldFree lift
where
lift (Put s a) = state (\t -> ((), t ++ [s])) >> return a
lift (Get f) = reader head >>= local tail . return . f -- This is wrong
mockConsole :: Teletype a -> [String] -> (a, [String])
mockConsole p inp = (a, s)
where
(a, s, _) = runRWS (interpRWS p) inp []
当运行 TeletypeRWS
"programs"时,环境中的第一个值不被移除:
*Main> mockConsole hello ["john", "18"]
((),["What is your name?","What is your age?","Hello, john!","You are john years old!"])
我对更新 Reader
有点不安,但我不知道还有什么方法可以访问列表中的下一个值。 TeletypeRWS
的类型是根据上面提到的练习选择的——所以我认为应该可以实现 interpRWS
.
我们不能使用foldFree
:它需要在continuation中是参数化的,所以我们不能在那里应用local
。相比之下,iterM
明确地给了我们实际的延拓而不是泛化,所以这会起作用。
interpRWS = iterM lift where
lift (Put s a) = modify (\t -> t ++ [s]) >> a
lift (Get f) = reader head >>= local tail . f