例如,涉及从提示符读取和写入命令的计算:
首先,我们将计算的“命令”描述为Functor数据类型
{-# LANGUAGE DeriveFunctor #-} data TeletypeF next = PrintLine String next | ReadLine (String -> next) deriving Functor
然后我们使用Free创建“ 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计算。
importControl.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计算IO
> interpretTeletype mockingbird hello hello goodbye goodbye this will go on forever this will go on forever