Coyoneda
圏論
Coyonedaは、Functorをdata構造として表現したもの
hs
code:hs
data Coyoneda f b = forall a. Coyoneda (a -> b) (f a)
-- GATD
data Coyoneda f b where
Coyoneda :: (a -> b) -> f a -> Coyoneda f b
instance Functor (Coyoneda f) where
fmap f (Coyoneda g fb) = Coyoneda (f . g) fb
上のようにGADTで定義すると、fmapとほぼ同じ見た目をしていることがわかりやすい
code:hs
fmap :: (a -> b) -> f a -> f b
purs
code:purs(hs)
newtype Coyoneda f a = Coyoneda (Exists (CoyonedaF f a))
data CoyonedaF f a i = CoyonedaF (i -> a) (f i)
コメント
ここで、CoyonedaはFree Functorと言えそう、と書いてて確かに、と思ったが、「Free Functor」という概念は実際あるみたい ただこれがCoyonedaと同じようなものを指しているのかどうかは読んでないので知らん
ユースケース
「*->*の任意のデータ型」と「Coyoneda」と「Freeモナド」を組み合わせれば手軽にMonadを作ることが出来る code:hs
newtype Natural f g = Natural (forall x. f x -> g x)
yoneda :: Functor f => f a -> Natural ((->) a) f
yoneda f = Natural $ \ax -> fmap ax f
code:hs
data Proc a = Action1 a | Action2 a | Action3 a
act1 = Free $ Coyoneda id (Action1 (Pure ()))
act2 = Free $ Coyoneda id (Action2 (Pure ()))
act3 = Free $ Coyoneda id (Action3 (Pure ()))
runProc :: Free (Coyoneda Proc) () -> IO ()
runProc (Pure ()) = putStrLn "end"
runProc (Free (Coyoneda f act)) = case act of
Action1 a -> putStrLn "act1" >> runProc (f a)
Action2 a -> putStrLn "act2" >> runProc (f a)
Action3 a -> putStrLn "act3" >> runProc (f a)
proc :: Free (Coyoneda Proc) ()
proc = do
act1
act2
act3
main = runProc proc