免費 monad 將 monadic 計算分為資料結構和直譯器
例如,涉及從提示讀取和寫入的命令的計算:
首先,我們將計算的命令描述為 Functor 資料型別
{-# LANGUAGE DeriveFunctor #-}
data TeletypeF next
= PrintLine String next
| ReadLine (String -> next)
deriving Functor
然後我們使用 Free
建立“免費 Monad over TeletypeF
”並構建一些基本操作。
import Control.Monad.Free (Free, liftF, iterM)
type Teletype = Free TeletypeF
printLine::String -> Teletype ()
printLine str = liftF (PrintLine str ())
readLine::Teletype String
readLine = liftF (ReadLine id)
由於 Free f
是 Monad
,每當 f
是 Functor
時,我們可以使用標準的 Monad
組合器(包括 do
表示法)來構建 Teletype
計算。
import Control.Monad -- we can use the standard combinators
echo::Teletype ()
echo = readLine >>= printLine
mockingbird::Teletype a
mockingbird = forever echo
最後,我們寫了一個直譯器,將 Teletype a
值轉化為我們知道如何使用 IO a
的東西
interpretTeletype::Teletype a -> IO a
interpretTeletype = foldFree run where
run::TeletypeF a -> IO a
run (PrintLine str x) = putStrLn *> return x
run (ReadLine f) = fmap f getLine
我們可以用來執行Teletype a
中的 Teletype a
計算
> interpretTeletype mockingbird
hello
hello
goodbye
goodbye
this will go on forever
this will go on forever