abt-0.1.0.0: src/Abt/Tutorial.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UnicodeSyntax #-}
module Abt.Tutorial where
import Abt.Class
import Abt.Types
import Abt.Concrete.LocallyNameless
import Control.Applicative
import Control.Monad.Trans
import Control.Monad.Trans.State.Strict
-- | We'll start off with a monad in which to manipulate ABTs; we'll need some
-- state for fresh variable generation.
--
newtype M α
= M
{ _M ∷ State Int α
} deriving (Functor, Applicative, Monad)
-- | We'll run an ABT computation by starting the variable counter at @0@.
--
runM ∷ M α → α
runM (M m) = evalState m 0
-- | Check out the source to see fresh variable generation.
--
instance MonadVar Var M where
fresh = M $ do
n ← get
let n' = n + 1
put n'
return $ Var Nothing n'
named a = do
v ← fresh
return $ v { _varName = Just a }
-- | Next, we'll define the operators for a tiny lambda calculus as a datatype
-- indexed by arities.
--
data Lang ns where
Lam ∷ Lang '[S Z]
Ap ∷ Lang '[Z,Z]
instance Show1 Lang where
show1 = \case
Lam → "lam"
Ap → "ap"
instance HEq1 Lang where
Lam === Lam = True
Ap === Ap = True
_ === _ = False
-- | Check out the source to see this example term: note that number of
-- arguments and presence of abstractions is guaranteed by the types. The
-- representation is not scope-safe (i.e. free variables are permitted), but
-- that's how we want it.
--
example ∷ M [Var]
example = do
x ← fresh
y ← fresh
let tm = Lam $$ x \\ (Ap $$ var x :* var y :* Nil) :* Nil
freeVars tm