packages feed

bound-0.1: examples/Simple.hs

module Simple where

import Data.Foldable
import Data.Traversable
import Control.Monad
import Control.Applicative
import Prelude hiding (foldr)
import Prelude.Extras
import Bound

-- \ x -> x
-- ghci> lam "x" (Var "x")
-- Lam (Var (Bound ()))

-- \ x -> x y
-- ghci> lam "x" (Var "x" :@ Var "y")
-- Lam (Var (Bound ()) :@ Var (Free (Var "y")))

-- \ y -> \x -> x y
-- ghci> lam "y" (lam "x" (Var "x" :@ Var "y"))
-- Lam (Lam (Var (Bound ()) :@ Var (Free (Var (Bound ())))))

infixl 9 :@

data Exp a = Var a | Exp a :@ Exp a | Lam (Scope () Exp a)
  deriving (Eq,Ord,Show,Read)


lam :: Eq a => a -> Exp a -> Exp a
lam v b = Lam (abstract1 v b)

instance Eq1 Exp      where (==#)      = (==)
instance Ord1 Exp     where compare1   = compare
instance Show1 Exp    where showsPrec1 = showsPrec
instance Read1 Exp    where readsPrec1 = readsPrec
instance Functor Exp  where fmap       = fmapDefault
instance Foldable Exp where foldMap    = foldMapDefault

instance Applicative Exp where
  pure  = Var
  (<*>) = ap

instance Traversable Exp where
  traverse f (Var a)  = Var <$> f a
  traverse f (x :@ y) = (:@) <$> traverse f x <*> traverse f y
  traverse f (Lam e)  = Lam <$> traverse f e

instance Monad Exp where
  return         = Var
  Var a    >>= f = f a
  (x :@ y) >>= f = (x >>= f) :@ (y >>= f)
  Lam e    >>= f = Lam (e >>>= f)