-
Notifications
You must be signed in to change notification settings - Fork 10
/
Unique.lhs
92 lines (72 loc) · 2.54 KB
/
Unique.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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
The Unique module implements the Normal Form function by
using Barendregt's variable convention, i.e., all bound
variables are unique.
> module Unique(nf) where
> import Lambda
> import qualified Data.Map as M
> import Control.Monad.State
> import IdInt
The first step is to make all variables unique.
Then normal form is computed by repeatedly performing
substitution (beta reduction) on the leftmost redex.
Normalization is run in a State monad with the next free variable.
> nf :: LC IdInt -> LC IdInt
> nf e = evalState (nf' e') i
> where (e', (i, _)) = runState (unique e) (firstBoundId, M.empty)
> type N a = State IdInt a
> nf' :: LC IdInt -> N (LC IdInt)
> nf' e@(Var _) = return e
> nf' (Lam x e) = liftM (Lam x) (nf' e)
> nf' (App f a) = do
> f' <- whnf f
> case f' of
> Lam x b -> subst x a b >>= nf'
> _ -> liftM2 App (nf' f') (nf' a)
Compute the weak head normal form.
> whnf :: LC IdInt -> N (LC IdInt)
> whnf e@(Var _) = return e
> whnf e@(Lam _ _) = return e
> whnf (App f a) = do
> f' <- whnf f
> case f' of
> Lam x b -> subst x a b >>= whnf
> _ -> return $ App f' a
Substitution proceeds by cloning the term that is inserted
at every place it is put.
(TODO: No need to clone $\lambda$-free terms.)
> subst :: IdInt -> LC IdInt -> LC IdInt -> N (LC IdInt)
> subst x s b = sub b
> where sub e@(Var v) | v == x = clone M.empty s
> | otherwise = return e
> sub (Lam v e) = liftM (Lam v) (sub e)
> sub (App f a) = liftM2 App (sub f) (sub a)
>
> clone m e@(Var v) = return $ maybe e Var (M.lookup v m)
> clone m (Lam v e) = do v' <- newVar; liftM (Lam v') (clone (M.insert v v' m) e)
> clone m (App f a) = liftM2 App (clone m f) (clone m a)
Create a fresh variable.
> newVar :: N IdInt
> newVar = do
> i <- get
> put (succ i)
> return i
Do the actual translation of the term to unique variables.
We keep mapping of old variable names to new variable name.
Free variables are just left alone since they are already
uniquely named.
> type U a = State (IdInt, M.Map IdInt IdInt) a
> unique :: LC IdInt -> U (LC IdInt)
> unique (Var v) = liftM Var (getVar v)
> unique (Lam v e) = liftM2 Lam (addVar v) (unique e)
> unique (App f a) = liftM2 App (unique f) (unique a)
Add a variable to the mapping.
> addVar :: IdInt -> U IdInt
> addVar v = do
> (i, m) <- get
> put (succ i, M.insert v i m)
> return i
Find an existing variable in the mapping.
> getVar :: IdInt -> U IdInt
> getVar v = do
> (_, m) <- get
> return $ maybe v id (M.lookup v m)