Adding Identifiers

The following steps are required to add identifiers:

  1. Create the concrete syntax
  2. Create inference rules
Note

In a bind, a variable cannot use itself in its declaration

Concrete Syntax

bind x in x + x

Inference Rules

Substitution Operator

[xv]t means 'replace all free instances of x in t with v'

bind

ava[iva]svsbind i= a in svsBindE

Identifiers

xIDE

Evaluating

When evaluating bind we have to substitute an identifier with a value.

To do this we recursively descend into the expressions within bind to substitute and evaluate. We first evaluate value we want to substitute. When we have this value we substitute it into the body of the bind.

We always substitute into the bound value of a but conditionally substitute into the scope of a bind if the identifiers collide.

Note

This method is not very efficient. It is mathematically correct and works as intended but recursively descends into our AST every time we hit a bind to substitute. There are much better ways to do this.

eval (Id s) = Nothing
eval (Bind i a b) = do { v  <- eval a;
						 b' <- subst i v b;
						 eval b'
						}

-- Takes the identifier, the value and the expression to sub into
subst :: String -> BAE -> BAE -> BAE
subst x v (Nat n) = (Nat n)
subst x v (Id x') = if x == x' then (Nat x) else (Id x')
subst x v (Plus l r ) = Plus((subst x v l) (subst x v r))
subst x v (Minus l r ) = Minus((subst x v l) (subst x v r))
subst x v (Mult l r ) = Mult((subst x v l) (subst x v r))
subst x v (Div l r ) = Div((subst x v l) (subst x v r))
subst x v (Bind x' v' t') = if x == x'
								then Bind( x' (subst x v v') t')
								else Bind( x' (subst x v v') (subst x v t'))

Deferring Substitution

Immediately substituting in the value of an identifier is very inefficient.

Instead we can "remember" what bindings exist in our scope and replace identifiers with values.

We will use an environment to do this.

Type Env = [(String, BAE)]

lookup :: A -> [(A, B)] -> Maybe B
-- We give our evaluator an environment to start with
eval :: Env -> BAE -> Maybe BAE
eval _ (Num n) = Just (Num n)
eval e (Plus l r) = do { (Num l') <- (eval e l);
						 (Num r') <- (eval e r);
						 return (Nat l' + r')
						}
eval e (Bind x a s) = do { a' <- (eval e a);
						   eval (x:a'):e s
						  }
eval e (Id x) = lookup x e
Note

We can curry the eval function with a default Env.

eval' = eval [("pi", (Num 3))]

This method has a few upsides as compared to using direct substitution.

evals uses direct substitution
eval uses deferred substitution

Definitions

Definitions

bind x = 5 in x + 4
-- 'x' is the identifier
bind x = 5 in x + 4
-- 'x' is bound to the left of '=' sign
bind x = 5 in x + 4
-- the scope is after the 'in'
bind x = 5 in x + 4
-- the value of 'x' is the expression between the '=' and 'in'; 
    '5' in this case
bind x = 5 in x + 4
-- 'x' is being used in 'x + 4'
bind x = x + 5 in x + 4
-- 'x' is being used in its bound value 'x + 5'