函数型なんたらの集い2014でモナドについて話してきた
最近私的にモナドが非常に熱いのでそれについて話してきました。
しかし資料としては要改善点が多いですね...
図入れるとか具体的なコード入れるとか色々出来たのですけど。
例
具体例をスライドに入れられなかったため、trivialな例を示す。
おおまかな雰囲気は感じられると思う。
明記してないけど、純粋関数は任意のモナド内でモナドとは関係なく使えます。
-- Derivingに必要 {-# LANGUAGE GeneralizedNewtypeDeriving #-} import Control.Applicative (Applicative) import Control.Monad.IO.Class (liftIO, MonadIO) import Control.Concurrent (threadDelay) -- DSLとなる型 (IO a のnewtype) newtype Hello a = Hello { unHello :: IO a } deriving (Functor, Applicative, Monad, MonadIO) -- DSLインターフェース(DSL定義) class Monad m => MonadHello m where getName :: m String echo :: String -> m () prompt :: m () wait :: m () -- HelloのDSL化 instance MonadHello Hello where getName = liftIO getLine echo = liftIO . putStrLn prompt = liftIO $ putStr "Enter your name: " wait = liftIO $ threadDelay 400000 -- HelloでSPECIALIZE {-# SPECIALIZE getName :: Hello String #-} {-# SPECIALIZE echo :: String -> Hello () #-} {-# SPECIALIZE prompt :: Hello () #-} {-# SPECIALIZE wait :: Hello () #-} -- run関数 (Hello DSLを実行し、IO上の効果とする) runHello :: Hello a -> IO a runHello = unHello -------------------------------------------------------------------------------- -- DSLを用いたロジック greet :: MonadHello m => m () greet = do echo "What's your name?" -- prompt表示 prompt name <- getName -- ifやcaseは問題なく使える case name of "" -> outputAndGreetAgain "Sorry, I can't hear you." "ruicc" -> outputAndGreetAgain "Hi, ruicc!" "quit" -> -- 実行終了 echo $ "Good bye!!" _ -> outputAndGreetAgain $ "Hello, " ++ name ++ "!" {-# SPECIALIZE greet :: Hello () #-} outputAndGreetAgain :: MonadHello m => String -> m () outputAndGreetAgain str = do -- 表示 echo str -- 待つ wait -- 再帰 greet {-# SPECIALIZE outputAndGreetAgain :: String -> Hello () #-} -------------------------------------------------------------------------------- main :: IO () main = do putStrLn "This is a DSL sample." putStrLn "---------------------" -- DSLを実行 (DSLの多相型(MonadHello m)をHelloに固定する) runHello $ greet