{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTs #-}
-- The definition of co-yoneda
data Coyoneda f b = forall a. Coyoneda (a -> b) (f a)
-- Coyoneda implements Functor
instance Functor (Coyoneda f
) where fmap f
(Coyoneda g h
) = Coyoneda
(f
. g
) h
-- The definition of the Free monad
data Free f a where
Pure :: a -> Free f a
Join :: f (Free f a) -> Free f a
instance Functor f
=> Applicative
(Free f
) where (<*>) = ap
-- Free f implements Functor when f is a functor
Pure a >>= f = f a
Join m
>>= f
= Join
$ fmap (>>= f
) m
-- A type alias for Free (Coyoneda f)
type M f = Free (Coyoneda f)
-- 'Lifts' an arbitrary f onto M f a
toM :: f a -> M f a
toM
= Join
. fmap Pure
. Coyoneda
id
-- A sample instruction for an operational monad
data Sample a where
-- Make the instruction monad
type SampleM = M Sample
-- Actions for each instruction
get = toM Get
put = toM . Put
-- Associates instructions and actual behaviours
runSampleM
:: SampleM a
-> IO a
runSampleM (Pure a) = pure a
runSampleM
(Join
(Coyoneda f Get
)) = getContents >>= runSampleM
. f
runSampleM
(Join
(Coyoneda f
(Put s
))) = putStrLn s
>>= runSampleM
. f
main = runSampleM $ do
get >>= put
ey0jIExBTkdVQUdFIEV4aXN0ZW50aWFsUXVhbnRpZmljYXRpb24gIy19CnstIyBMQU5HVUFHRSBHQURUcyAjLX0KCmltcG9ydCBDb250cm9sLk1vbmFkCgotLSBUaGUgZGVmaW5pdGlvbiBvZiBjby15b25lZGEKZGF0YSBDb3lvbmVkYSBmIGIgPSBmb3JhbGwgYS4gQ295b25lZGEgKGEgLT4gYikgKGYgYSkKCi0tIENveW9uZWRhIGltcGxlbWVudHMgRnVuY3RvcgppbnN0YW5jZSBGdW5jdG9yIChDb3lvbmVkYSBmKSB3aGVyZQogICAgZm1hcCBmIChDb3lvbmVkYSBnIGgpID0gQ295b25lZGEgKGYgLiBnKSBoCgotLSBUaGUgZGVmaW5pdGlvbiBvZiB0aGUgRnJlZSBtb25hZApkYXRhIEZyZWUgZiBhIHdoZXJlCiAgUHVyZSA6OiBhIC0+IEZyZWUgZiBhCiAgSm9pbiA6OiBmIChGcmVlIGYgYSkgLT4gRnJlZSBmIGEKCmluc3RhbmNlIEZ1bmN0b3IgZiA9PiBGdW5jdG9yIChGcmVlIGYpIHdoZXJlCiAgZm1hcCA9IGxpZnRNCgppbnN0YW5jZSBGdW5jdG9yIGYgPT4gQXBwbGljYXRpdmUgKEZyZWUgZikgd2hlcmUKICBwdXJlID0gcmV0dXJuCiAgKDwqPikgPSBhcAoKLS0gRnJlZSBmIGltcGxlbWVudHMgRnVuY3RvciB3aGVuIGYgaXMgYSBmdW5jdG9yCmluc3RhbmNlIEZ1bmN0b3IgZiA9PiBNb25hZCAoRnJlZSBmKSB3aGVyZQogIHJldHVybiA9IFB1cmUKICBQdXJlIGEgPj49IGYgPSBmIGEKICBKb2luIG0gPj49IGYgPSBKb2luICQgZm1hcCAoPj49IGYpIG0KCi0tIEEgdHlwZSBhbGlhcyBmb3IgRnJlZSAoQ295b25lZGEgZikKdHlwZSBNIGYgPSBGcmVlIChDb3lvbmVkYSBmKQoKLS0gJ0xpZnRzJyBhbiBhcmJpdHJhcnkgZiBvbnRvIE0gZiBhCnRvTSA6OiBmIGEgLT4gTSBmIGEKdG9NID0gSm9pbiAuIGZtYXAgUHVyZSAuIENveW9uZWRhIGlkCgotLSBBIHNhbXBsZSBpbnN0cnVjdGlvbiBmb3IgYW4gb3BlcmF0aW9uYWwgbW9uYWQKZGF0YSBTYW1wbGUgYSB3aGVyZQogIEdldCA6OiBTYW1wbGUgU3RyaW5nCiAgUHV0IDo6IFN0cmluZyAtPiBTYW1wbGUgKCkKCi0tIE1ha2UgdGhlIGluc3RydWN0aW9uIG1vbmFkCnR5cGUgU2FtcGxlTSA9IE0gU2FtcGxlCgotLSBBY3Rpb25zIGZvciBlYWNoIGluc3RydWN0aW9uCmdldCA6OiBTYW1wbGVNIFN0cmluZwpnZXQgPSB0b00gR2V0CnB1dCA6OiBTdHJpbmcgLT4gU2FtcGxlTSAoKQpwdXQgPSB0b00gLiBQdXQKCi0tIEFzc29jaWF0ZXMgaW5zdHJ1Y3Rpb25zIGFuZCBhY3R1YWwgYmVoYXZpb3VycwpydW5TYW1wbGVNIDo6IFNhbXBsZU0gYSAtPiBJTyBhCnJ1blNhbXBsZU0gKFB1cmUgYSkgPSBwdXJlIGEKcnVuU2FtcGxlTSAoSm9pbiAoQ295b25lZGEgZiBHZXQpKSA9IGdldENvbnRlbnRzID4+PSBydW5TYW1wbGVNIC4gZgpydW5TYW1wbGVNIChKb2luIChDb3lvbmVkYSBmIChQdXQgcykpKSA9IHB1dFN0ckxuIHMgPj49IHJ1blNhbXBsZU0gLiBmCgptYWluIDo6IElPICgpCm1haW4gPSBydW5TYW1wbGVNICQgZG8KICBnZXQgPj49IHB1dA==