rebound-0.1.0.0: examples/ScopeCheck.hs
-- |
-- Module : ScopeCheck
-- Description : Scope checking the Untyped lambda calculus
-- Stability : experimental
--
-- This module demonstrates a translation from unscoped to well-scoped terms
module ScopeCheck where
import Rebound
import Rebound.Bind.Single
import Data.Maybe (fromJust)
import LC qualified
import Rebound.Lib
-- | Named representation for the untyped lambda calculus
-- The type parameter 'a' is the variable type
data Exp (a :: Type) where
Var :: a -> Exp a
Lam :: a -> Exp a -> Exp a
App :: Exp a -> Exp a -> Exp a
-- | Convert a named expression to deBruijn indices, checking to make
-- sure that the expression is well scoped
scopeCheck :: (Eq a) => Exp a -> Maybe (LC.Exp Z)
scopeCheck = to []
where
to :: (Eq a) => [(a, Fin n)] -> Exp a -> Maybe (LC.Exp n)
to vs (Var v) = do
x <- lookup v vs
return $ LC.Var x
to vs (Lam v b) = do
b' <- to ((v, FZ) : map (fmap FS) vs) b
return $ LC.Lam (bind b')
to vs (App f a) = do
f' <- to vs f
a' <- to vs a
return $ LC.App f' a'
----------------------------------------------
-- Examples
----------------------------------------------
-- | Identity function
idExp :: Exp String
idExp = Lam "x" (Var "x")
-- | "True"
trueExp :: Exp String
trueExp = Lam "x" (Lam "y" (Var "x"))
-- | An ill-scoped term (`y` is never bound)
illScoped :: Exp String
illScoped = Lam "x" (Var "y")
-- >>> scopeCheck idExp
-- Just (λ. 0)
-- >>> scopeCheck trueExp
-- Just (λ. (λ. 1))
-- >>> scopeCheck illScoped
-- Nothing