11. Freer Monadとは
Monadをデータ型として表したもの
data Freer f a where
Pure :: a -> Freer f a
Impure :: f a -> (a -> Freer f b) -> Freer f b
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
12. Freerとの比較
FreeApとFreerのデータ構造を比較する
e5 :: FreeAp (Exc String) Integer
e5 = ImpureAp (Exc "foo") $ ImpureAp (Exc "bar") $ Pure (+)
e6 :: Freer (Exc String) Integer
e6 = Impure (Exc "foo") $ a -> Impure (Exc "bar") $ b ->
Pure (a + b)
14. Free Applicativeの応用
エラーの収集ができる
runExc :: FreeAp (Exc e) a -> Either [e] a
runExc (Pure a) = Right a
runExc (ImpureAp (Exc e) k) =
case runExc k of
Right _ -> Left [e]
Left es -> Left (e : es)
> runExc e5
Left ["foo","bar"]
15. Free Applicativeの応用
平行計算ができる
runAsync :: FreeAp IO a -> IO a
runAsync (Pure a) = pure a
runAsync (ImpureAp x k) =
do
a <- async x
k' <- runAsync k
x' <- wait a
return $ k' x'
20. Extensible Eff Applicative
定義はFree Applicativeとそこまで変わらない
data EffAp r a where
Pure :: a -> EffAp r a
ImpureAp :: Union r a -> EffAp r (a -> b) -> EffAp r b
21. Extensible Eff Applicative
重要なのは他の作用を跨いだhandlerを書けるかどうか
runExc :: EffAp (Exc e : r) a -> EffAp r (Either [e] a)
runExc (Pure a) = Pure $ Right a
runExc (ImpureAp u k) =
case decomp u of
Right (Exc e) -> fmap f (runExc k) where
f (Right _) = Left [e]
f (Left es) = Left (e : es)
Left u -> ImpureAp u $ fmap f (runExc k) where
f e a = fmap (k -> k a) e
22. Extensible Eff Applicative
IOは終端で処理するしかない
runAsync :: EffAp '[IO] a -> IO a
runAsync (Pure a) = pure a
runAsync (ImpureAp u k) =
do
let Right x = decomp u
a <- async x
k' <- runAsync k
x' <- wait a
return $ k' x'
26. effect handlers
ここで一般化されたハンドラについて考える
以下はEffの例
handle_relay :: (a -> Eff r w) ->
(forall v. t v -> (v -> Eff r w) -> Eff r w) ->
Eff (t : r ) a -> Eff r w
handle_relay ret _ (Pure x) = ret x
handle_relay ret h (Impure u q) = case decomp u of
Right x -> h x k
Left u -> Impure u k
where k = handle_relay ret h . q
27. effect handlers
あまりイケてないがそれっぽいものは書ける
handle_relay :: Functor f =>
(forall a. a -> EffAp r (f a)) ->
(forall a b. t a -> EffAp r (f (a -> b)) -> EffAp r (f b)) ->
EffAp (t : r ) a -> EffAp r (f a)
handle_relay ret _ (Pure x) = ret x
handle_relay ret h (ImpureAp u q) = case decomp u of
Right x -> h x k
Left u -> ImpureAp u (fmap f k)
where
k = handle_relay ret h q
f x a = fmap (k -> k a) x
28. effect handlers
ReaderとWriterの例
runReader :: i -> EffAp (Reader i : r) a -> EffAp r a
runReader i = coerce . handle_relay
(Pure . Identity)
(Ask -> fmap ((Identity k) -> Identity $ k i))
runWriter :: Monoid w => EffAp (Writer w : r) a -> EffAp r (w, a)
runWriter = handle_relay
(a -> Pure (mempty, a))
((Tell v) -> fmap ((w, k) -> (mappend v w, k ())))
32. Effとの組み合わせ(コンストラクタ)
コンストラクタに含める
data Eff r a where
Pure :: a -> Eff r a
Impure :: Union r a -> (a -> Eff r b) -> Eff r b
ImpureAp :: Union r a -> Eff r (a -> b) -> Eff r b
35. Effとの組み合わせ(型パラメータ)
型パラメータを増やす
data Eff h r a where
Pure :: a -> Eff h r a
Impure :: Union r a -> h (Eff h r) a b -> Eff h r b
data Apply f a b where
Apply :: f (a -> b) -> Apply f a b
data Bind f a b where
Bind :: (a -> f b) -> Bind f a b