packages feed

hoq-0.3: src/Syntax/Term.hs

{-# LANGUAGE RankNTypes #-}

module Syntax.Term
    ( Term(..), Scoped(..)
    , capply, cvar, bvar, apps
    , instantiate1
    , Closed(..), closed
    ) where

import Data.Void
import Data.Monoid
import Data.Foldable
import Data.Traversable
import Data.Bifunctor
import Data.Bifoldable
import Data.Bitraversable
import Control.Applicative
import Control.Monad

data Term p a
    = Var a [Term p a]
    | Apply p [Term p a]
    | Lambda (Term p (Scoped a))

instance Functor  (Term p) where fmap = fmapDefault
instance Foldable (Term p) where foldMap = foldMapDefault
instance Bifunctor  Term where bimap = bimapDefault
instance Bifoldable Term where bifoldMap = bifoldMapDefault
instance Traversable (Term p) where traverse = bitraverse pure

instance Bitraversable Term where
    bitraverse f g (Var a ts) = Var <$> g a <*> traverse (bitraverse f g) ts
    bitraverse f g (Apply p ts) = Apply <$> f p <*> traverse (bitraverse f g) ts
    bitraverse f g (Lambda t) = Lambda <$> bitraverse f (traverse g) t

instance Applicative (Term p) where
    pure    = cvar
    (<*>)   = ap

instance Monad (Term p) where
    return           = cvar
    Var a ts   >>= k = apps (k a) $ map (>>= k) ts
    Apply p ts >>= k = Apply p $ map (>>= k) ts
    Lambda s   >>= k = Lambda $ s >>= \v -> case v of
        Free a -> fmap Free (k a)
        Bound  -> return Bound

capply :: p -> Term p a
capply p = Apply p []

cvar :: a -> Term p a
cvar a = Var a []

bvar :: Term p (Scoped a)
bvar = cvar Bound

apps :: Term s a -> [Term s a] -> Term s a
apps t [] = t
apps (Lambda t) (t1:ts) = apps (instantiate1 t1 t) ts
apps (Apply a as) ts = Apply a (as ++ ts)
apps (Var a as) ts = Var a (as ++ ts)

newtype Closed f = Closed { open :: forall a. f a }

data Scoped a = Free a | Bound

instance Eq a => Eq (Scoped a) where
    Bound == Bound = True
    Free a == Free a' = a == a'
    _ == _ = False

instance Functor Scoped where
    fmap _ Bound = Bound
    fmap f (Free a)  = Free (f a)

instance Foldable Scoped where
    foldMap _ Bound = mempty
    foldMap f (Free a)  = f a

instance Traversable Scoped where
    traverse _ Bound = pure Bound
    traverse f (Free a) = Free <$> f a

instance Applicative Scoped where
    pure = Free
    Bound <*> _ = Bound
    _ <*> Bound = Bound
    Free f <*> Free a = Free (f a)

instantiate1 :: Monad f => f a -> f (Scoped a) -> f a
instantiate1 s t = t >>= \v -> case v of
    Bound   -> s
    Free a  -> return a

closed :: Functor f => f Void -> Closed f
closed t = Closed (vacuous t)