5. de nition of Monad
cf.
GHC.Base#Monad
class Applicative m => Monad m where
(>>=) :: forall a b. m a -> (a -> m b) -> m b
(>>) :: forall a b. m a -> m b -> m b
m >> k = m >>= _ -> k
{-# INLINE (>>) #-}
return :: a -> m a
return = pure
fail :: String -> m a
fail s = errorWithoutStackTrace s
scalaz/Monad.scala
9. for expression (Scala)
↓ desugar
val a = Some(2)
val b = Some(3)
val c = for {
x <- a
y <- b
} yield x * y
val a = Some(2)
val b = Some(3)
val c = a.flatMap { x =>
b.map { y =>
x * y
}
}
11. de nition of Free
cf.
Control/Monad/Free.hs
data Free f a = Pure a | Free (f (Free f a))
instance Functor f => Monad (Free f) where
return = pure
{-# INLINE return #-}
Pure a >>= f = f a
Free m >>= f = Free ((>>= f) <$> m)
scalaz/Free.scala
12. リストのような再帰的データ構造
data [] a = [] | a : [a]
f が Functor ⇒ Free f は Monad
→ Functor のインスタンスを Free で包めば
Monad として扱える
※ GHC拡張で Functor を⾃動導出することも:
DeriveFunctor
18. RPNExpr を Functor にする
instance Functor (RPNExpr n) where
fmap f (Number n expr) = Number n $ f expr
fmap f (Add expr) = Add $ f expr
fmap f (Sub expr) = Sub $ f expr
fmap f (Mul expr) = Mul $ f expr
fmap _ End = End
19. RPNExpr を Free で包んで RPN Monad として扱う
type RPN a b = Free (RPNExpr a) b
liftF :: (Functor f) => f r -> Free f r
liftF = Free . fmap Pure
num :: a -> RPN a ()
num n = liftF $ Number n ()
add :: RPN a ()
add = liftF $ Add ()
sub :: RPN a ()
sub = liftF $ Sub ()
mul :: RPN a ()
mul = liftF $ Mul ()
end :: RPN a b
end = liftF End
20. RPN モナド(RPNのDSL = AST)を試してみる
> :{
| expr1 :: RPN Double ()
| expr1 = do
| num 8
| num 6
| num 1
| sub
| mul
| :}
> expr1
Free (Number 8.0 (Free (Number 6.0 (Free (Number 1.0
(Free (Sub (Free (Mul (Pure ()))))))))))
24. ⽂字列をRPNのASTに変換する関数 parse
parse :: (Read a) => String -> Either String (RPN a ())
parse = foldM rpn (Pure ()) . reverse . words
where
rpn e "+" = Right . Free $ Add e
rpn e "-" = Right . Free $ Sub e
rpn e "*" = Right . Free $ Mul e
rpn _ "." = Right $ Free End
rpn e n = case reads n of
[(v,_)] -> Right . Free $ Number v e
_ -> Left "invalid input"