-
Notifications
You must be signed in to change notification settings - Fork 1
/
lambda-calculator.hs
72 lines (60 loc) · 2.41 KB
/
lambda-calculator.hs
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
import Data.List
import Data.Maybe
type Symb = String
infixl 2 :@
infix 1 `alphaEq`
infix 1 `betaEq`
data Expr
= Var Symb
| Expr :@ Expr
| Lam Symb Expr
deriving (Eq, Read, Show)
------------------------ 1 ------------------------
-- возвращающая список свободных переменных терма.
freeVars :: Expr -> [Symb]
freeVars (Var x) = [x]
freeVars (m :@ n) = freeVars m `union` freeVars n
freeVars (Lam x m) = delete x (freeVars m)
-- переименование связанных переменных
renameVar :: String -> Expr -> Expr -> Symb
renameVar x m n
| x `notElem` freeVars n && x `notElem` freeVars m = x
| otherwise = renameVar (x ++ "'") n m
-- подстановки терма n вместо всех свободных вхождений переменной v в терме m
subst :: Symb -> Expr -> Expr -> Expr
subst v n (m :@ n') = subst v n m :@ subst v n n'
subst v n (Var x)
| v == x = n
| otherwise = Var x
subst v n (Lam x m)
| v == x = Lam x m
| x `elem` freeVars n = Lam (renameVar x n m) (subst v n (subst x (Var $ renameVar x n m) m))
| otherwise = Lam x (subst v n m)
------------------------ 2 ------------------------
-- проверка a-эквивалентности двух термов
alphaEq :: Expr -> Expr -> Bool
alphaEq (m :@ n) (m' :@ n')
| alphaEq m m' && alphaEq n n' = True
| otherwise = False
alphaEq (Lam x m) (Lam y n)
| alphaEq (subst x (Var $ renameVar x m n) m) (subst y (Var $ renameVar x m n) n) = True
| otherwise = False
alphaEq (Var x) (Var y) = x == y
alphaEq x y = False
------------------------ 3 ------------------------
-- оддношаговая b-редукция, сокращающая левый внешний редекс в терме, если можно
reduceOnce :: Expr -> Maybe Expr
reduceOnce (Var x) = Nothing
reduceOnce ((Lam x m) :@ n) = Just (subst x n m)
reduceOnce (Lam x m) = fmap (Lam x) (reduceOnce m)
reduceOnce (m :@ n) = case reduceOnce m of
Just y -> Just (y :@ n)
Nothing -> fmap (m :@) (reduceOnce n)
------------------------ 4 ------------------------
-- многошаговая b-редукция
nf :: Expr -> Expr
nf x = if isNothing (reduceOnce x) then x else nf (fromJust $ reduceOnce x)
------------------------ 5 ------------------------
-- проверка b-эквивалентности двух термов
betaEq :: Expr -> Expr -> Bool
betaEq m n = alphaEq (nf m) (nf n)