其他答案忽略了多么简单free
做这个! :) 目前你有
{-# LANGUAGE DeriveFunctor #-}
import Control.Monad.Free
data FooF x = Foo String x
| Bar Int x
deriving (Functor)
type Foo = Free FooF
program :: Free FooF ()
program = do
liftF (Foo "Hello" ())
liftF (Bar 1 ())
liftF (Foo "Bye" ())
printFoo :: Foo () -> IO ()
printFoo (Free (Foo s n)) = print s >> printFoo n
printFoo (Free (Bar i n)) = print i >> printFoo n
printFoo (Pure a) = return a
这使
*Main> printFoo program
"Hello"
1
"Bye"
那很好,但是iterM
可以为您做必要的管道工作
printFooF :: FooF (IO a) -> IO a
printFooF (Foo s x) = print s >> x
printFooF (Bar i x) = print i >> x
printFooBetter :: Foo () -> IO ()
printFooBetter = iterM printFooF
然后我们得到
*Main> printFooBetter program
"Hello"
1
"Bye"
好吧,太好了,和以前一样。但printFooF
给我们更多
灵活地按照您想要的方式增强翻译器
printFooFExtra :: FooF (IO a) -> IO a
printFooFExtra = (print "stuff before IO action" >>)
. printFooF
. fmap (print "stuff after IO action" >>)
printFooExtra :: Foo () -> IO ()
printFooExtra = iterM printFooFExtra
然后我们得到
*Main> printFooExtra program
"stuff before IO action"
"Hello"
"stuff after IO action"
"stuff before IO action"
1
"stuff after IO action"
"stuff before IO action"
"Bye"
"stuff after IO action"
感谢 Gabriel Gonzalez 推广自由单子和 Edward Kmett
用于编写库! :)