http://www.haskellforall.com/2012/06/you-could-have-invented-free-monads.dddd の内容を試しに再実装してみただけ。このエントリはわかりやすいエントリなので読んだ方がよい。
自由モナドは(値ではなく)関手をリスト的に構成したものなのだけど、これがインタプリタのモデルに奇麗にハマる。
% runghc
{-# LANGUAGE DeriveFunctor #-}
module Main (main) where
import Control.Monad.Free
data OreLangF a =
Print String a
| GetLength String (Int -> a)
| Done deriving Functor
type OreLang = Free OreLangF
orePrint :: String -> OreLang ()
orePrint str = liftF $ Print str ()
oreLength :: String -> OreLang Int
oreLength str = liftF $ GetLength str id
done :: OreLang ()
done = liftF $ Done
run :: OreLang r -> IO ()
run (Free f) = case f of
Print s next -> do
print s
run next
GetLength s g -> do
let next = g (length s)
run next
Done -> return ()
run (Pure _) = return ()
main :: IO ()
main = run $ do
orePrint "ABCDE"
i <- oreLength "123456789"
orePrint . show $ i
done
全てが美しくハマり過ぎててむしろ気持ち悪いくらい。
"ABCDE"
"9"