我正在尝试扩展此blog post中解释的玩具示例。
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
module FreeToy where
import Control.Monad.State
import Control.Monad.Free
import Data.Map (Map)
import qualified Data.Map as M
-- defining commands
data Toy a next =
Output a next
| AnnoyingOutput a (String -> next)
| Done
deriving (Functor)
-- lifing commands to free monad level
output :: a -> Free (Toy a) ()
output x = liftF $ Output x ()
annoyingOutput :: a -> Free (Toy a) {-some type-}
annoyingOutput x = liftF $ AnnoyingOutput x {-some function-}
done :: Free (Toy a) r
done = liftF $ Done
-- defining one of the interpreter
runToy :: (Show a, Show r) => Free (Toy a) r -> String
runToy (Free (Output a x)) =
"output " ++ show a ++ "\n" ++ runToy x
runToy (Free (AnnoyingOutput a f)) =
"annoying output " ++ show a ++ runToy (f "blah blah blah \n")
runToy (Free Done) =
"done\n"
runToy (Pure r) =
"return " ++ show r ++ "\n"
我尝试添加的新内容是AnnoyingOutput a (String -> next)
这会占用一些东西并返回String消息。我是struct,同时使用liftF
函数将其提升到Free monad级别。请帮助我填补空白,正确的解释是可观的。
编辑:添加示例
module Main where
import FreeToy
import Control.Monad.Free
program :: Free (Toy String) ()
program = do
output "something"
x <- annoyingOutput "something else"
output x
done
main :: IO ()
main = putStrLn $ runToy program