-
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
-- Simple untyped lambda calculus interpreter using de Bruijin indices
-- WRONG: https://jameshfisher.com/2018/03/15/a-lambda-calculus-interpreter-in-haskell/
-- See STLC.lean for a better implementation
inductive Term where
| A : Term → Term → Term
| L : Term → Term
| V : Nat → Term
partial def reduce : Term → Term
| .A fn arg =>
match reduce fn with
| .L body =>
let rec incr d
| .A fn arg => .A (incr (d + 1) fn) (incr (d + 1) arg)
| .L body => .L <| incr (d + 1) body
| .V x => .V <| if d ≤ x then x + 1 else x
let rec sub n s
| .A fn arg => .A (sub n s fn) (sub n s arg)
| .L body => .L <| sub (n + 1) (incr 0 s) body
| .V x => if x = n then s else .V (if n < x then x - 1 else x)
reduce <| sub 0 (reduce arg) body
| other => .A other arg
| other => other
def I := Term.L (.V 0)
def K := Term.L <| Term.L (.V 1)
def S := Term.L
(.L
(.L
(.A
(.A (.V 2) (.V 0))
(.A (.V 1) (.V 0))
)
)
)
def Y := Term.L
(.A
(.L
(.A (.V 1) (.A (.V 0) (.V 0)))
)
(.L
(.A (.V 1) (.A (.V 0) (.V 0)))
)
)
#eval reduce <| .A (.A (.A S K) I) (.A (.A K I) S)
#eval reduce <| .A (.A (.A S K) I) K
-- Doesn't terminate
-- #eval reduce <| .A Y I