-
Notifications
You must be signed in to change notification settings - Fork 10
/
Simple.lhs
75 lines (64 loc) · 2.59 KB
/
Simple.lhs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
The Simple module implements the Normal Form function by
using a na\"{i}ve version of substitution.
> module Simple(nf) where
> import Data.List(union, (\\))
> import Lambda
> import IdInt
The normal form is computed by repeatedly performing
substitution ($\beta$-reduction) on the leftmost redex.
Variables and abstractions are easy, but in the case of
an application we must compute the function to see if
it is an abstraction. The function cannot be computed
with the {\tt nf} function since it could perform
non-leftmost reductions. Instead we use the {\tt whnf}
function.
> nf :: LC IdInt -> LC IdInt
> nf e@(Var _) = e
> nf (Lam x e) = Lam x (nf e)
> nf (App f a) =
> case whnf f of
> Lam x b -> nf (subst x a b)
> f' -> App (nf f') (nf a)
Compute the weak head normal form. It is similar to computing the normal form,
but it does not reduce under $\lambda$, nor does it touch an application
that is not a $\beta$-redex.
> whnf :: LC IdInt -> LC IdInt
> whnf e@(Var _) = e
> whnf e@(Lam _ _) = e
> whnf (App f a) =
> case whnf f of
> Lam x b -> whnf (subst x a b)
> f' -> App f' a
Substitution has only one interesting case, the abstraction.
For abstraction there are three cases:
if the bound variable, {\tt v}, is equal to the variable we
are replacing, {\tt x}, then we are done,
if the bound variable is in set set of free variables
of the substituted expression then there would be
an accidental capture and we rename it,
otherwise the substitution just continues.
How should the new variable be picked when doing the
renaming? The new variable must not be in the set of
free variables of {\tt s} since this would case another
accidental capture, nor must it be among the free variables
of {\tt e'} since this could cause another accidental
capture. Conservatively, we avoid all variables occuring
in the original {\tt b} to fulfill the second requirement.
> subst :: IdInt -> LC IdInt -> LC IdInt -> LC IdInt
> subst x s b = sub b
> where sub e@(Var v) | v == x = s
> | otherwise = e
> sub e@(Lam v e') | v == x = e
> | v `elem` fvs = Lam v' (sub e'')
> | otherwise = Lam v (sub e')
> where v' = newId vs
> e'' = subst v (Var v') e'
> sub (App f a) = App (sub f) (sub a)
>
> fvs = freeVars s
> vs = fvs `union` allVars b
Get a variable which is not in the given set.
Do this simply by generating all variables and picking the
first not in the given set.
> newId :: [IdInt] -> IdInt
> newId vs = head ([firstBoundId .. ] \\ vs)