blob: c733617854376335dcd26b902e6fe9fd0b83ecad (
plain)
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
module LambdaCalc where
import Data.Char (isSpace)
data Term = Variable String
| Abstraction Term Term
| Application Term Term
deriving (Eq)
instance Show Term where
show (Variable s) = s
show (Abstraction varName body) = '\x03BB':show varName ++ '.':show body
show (Application x y) = x' ++ ' ':y'
where
x' = if isAbstraction x then '(':show x ++ ")" else show x
y' = if isVariable y then show y else '(':show y ++ ")"
var :: String -> Term
var "" = error "cannot name a variable with an empty string"
var s
| any ( \c -> isSpace c || c `elem` "().\x03BB") s = error "name has forbidden characters"
| otherwise = Variable s
lambda :: String -> Term -> Term
lambda s t = Abstraction (var s) t
apply :: Term -> Term -> Term
apply = Application
infixl 6 <+>
(<+>) :: Term -> Term -> Term
(<+>) = apply
-- same as apply or <+>, but also beta reduces the result
infixl 6 <++>
(<++>) :: Term -> Term -> Term
x <++> y = betaReduce $ x <+> y
isVariable :: Term -> Bool
isVariable (Variable _) = True
isVariable _ = False
isAbstraction :: Term -> Bool
isAbstraction (Abstraction _ _) = True
isAbstraction _ = False
isApplication :: Term -> Bool
isApplication (Application _ _) = True
isApplication _ = False
isNormal :: Term -> Bool
isNormal (Variable _) = True
isNormal (Abstraction _ b) = isNormal b
isNormal (Application x y) = not (isAbstraction x) && isNormal x && isNormal y
betaStep :: Term -> Term
betaStep (Variable v) = Variable v
betaStep (Abstraction v body) = Abstraction v $ betaStep body
betaStep (Application x y)
| isAbstraction x = deAbstract x y
| otherwise = Application (betaStep x) (betaStep y)
betaPath :: Term -> [Term]
betaPath e
| isNormal e = [e]
| otherwise = e:betaPath (betaStep e)
betaReduce :: Term -> Term
betaReduce = last . betaPath
deAbstract :: Term -> Term -> Term
deAbstract (Abstraction v body) arg = go body
where
go v'@(Variable _)
| v == v' = arg
| otherwise = v'
go a@(Abstraction v' body')
| v == v' = a
| otherwise = Abstraction v' $ go body'
go (Application x y) = Application (go x) (go y)
deAbstract _ _ = error "deAbstract: first argument must an abstraction"
{- Common combinators -}
combI :: Term
combI = lambda "x" $ var "x"
identity :: Term
identity = combI
combK :: Term
combK = lambda "a" $ lambda "b" $ var "a"
constant :: Term
constant = combK
combKI :: Term
combKI = lambda "a" $ lambda "b" $ var "b"
combB :: Term
combB = lambda "f" $ lambda "g" $ lambda "a" body
where
body = var "f" <+> (var "g" <+> var "a")
compose :: Term
compose = combB
combC :: Term
combC = lambda "f" $ lambda "a" $ lambda "b" $ var "f" <+> var "b" <+> var "a"
{- Boolean values and operations -}
-- assumes valid input
fromBool :: Term -> Bool
fromBool e = case e <++> var "_TRUE" <++> var "_FALSE" of
Variable "_TRUE" -> True
Variable "_FALSE" -> False
_ -> error "could not recognize lambda expression as boolean"
bTrue :: Term
bTrue = lambda "x" $ lambda "y" $ var "x"
bFalse :: Term
bFalse = lambda "x" $ lambda "y" $ var "y"
bNot :: Term
bNot = lambda "b" $ var "b" <++> bFalse <++> bTrue
bOr :: Term
bOr = lambda "p" $ lambda "q" body
where
body = var "p" <++> var "p" <++> var "q"
bAnd :: Term
bAnd = lambda "p" $ lambda "q" body
where
body = var "p" <++> var "q" <++> var "p"
bEq :: Term
bEq = lambda "p" $ lambda "q" body
where
body = var "p" <++> var "q" <++> (bNot <++> var "q")
bXor :: Term
bXor = lambda "p" $ lambda "q" body
where
body = var "p" <++> (bNot <++> var "q") <++> var "q"
bImplies :: Term
bImplies = lambda "p" $ lambda "q" body
where
body = var "p" <++> var "q" <++> bTrue
bConverse :: Term
bConverse = combC <++> bImplies
|