Skip to content

Instantly share code, notes, and snippets.

@gatlin
Created June 10, 2014 07:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gatlin/8d835a0467ab64e8a845 to your computer and use it in GitHub Desktop.
Save gatlin/8d835a0467ab64e8a845 to your computer and use it in GitHub Desktop.
Two things in one: functors implemented as algebraic data types; and a free monad derived automatically from it. No typeclasses necessary!
{-# LANGUAGE RankNTypes #-}
data F f = F {
_map :: forall a b. (a -> b) -> f a -> f b
}
data Mu f a
= Term { retract :: a }
| Cont (f (Mu f a))
unit :: a -> Mu f a
unit = Term
yield :: a -> Mu f a
yield = Term
bind :: F f -> Mu f a -> (a -> Mu f b) -> Mu f b
bind i arg fn = case arg of
Term t -> fn t
Cont k -> Cont (map (bind' fn) k)
where map = _map i
bind' = flip (bind i)
sequence' i x = case x of
[] -> unit []
m:ms -> m >>= \x ->
sequence' i ms >>= \xs ->
unit (x:xs)
where
(>>=) = bind i
{-
- And now to demonstrate this plumbing on a common data type
-}
data Optional s
= Nil
| Some s
deriving (Show)
fOptional :: F Optional
fOptional = F {
_map = \f x -> case x of
Nil -> Nil
Some s -> Some $ f s
}
nil = Cont Nil
some = Term
runOptional :: Mu Optional a -> Optional a
runOptional (Term t) = Some t
runOptional (Cont k) = case k of
Nil -> Nil
Some v -> runOptional v
testOptional1 = some 5 >>= \a ->
some 6 >>= \b ->
yield $ a * b
where (>>=) = bind fOptional
testOptional2 = some 5 >>= \a ->
nil >>= \b ->
some 6 >>= \c ->
yield $ a * c
where (>>=) = bind fOptional
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment