Skip to content

Commit 3df3f88

Browse files
author
Filippo Costa
committed
Rewrite the implementation using Python lambdas
1 parent 370e95a commit 3df3f88

File tree

2 files changed

+129
-51
lines changed

2 files changed

+129
-51
lines changed

lambda.lambda

-51
This file was deleted.

lambda.py

+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
# This Python script declares a binary lambda calculus interpreter. The
5+
# interpreter is written in untyped lambda calculus itself (i.e. only function
6+
# declarations and applications are allowed). Native recursion in particular
7+
# is disallowed.
8+
9+
# All functions allow prefix notation; for example:
10+
# NOT (TRUE)
11+
# _1ST (tuple)
12+
# EQ (n) (m)
13+
14+
# Utils
15+
# =====
16+
17+
# Implements recursion; for example:
18+
# FACTORIAL = Y (lambda f: lambda n: 1 if n == 0 else n * f(n-1))
19+
# See https://en.wikipedia.org/wiki/Fixed-point_combinator#Fixed_point_combinators_in_lambda_calculus
20+
# for more.
21+
Y = lambda f: (
22+
(lambda x: f (lambda y: x (x) (y)))
23+
(lambda x: f (lambda y: x (x) (y))))
24+
25+
ID = lambda x: x
26+
27+
# Booleans
28+
# ========
29+
30+
TRUE = lambda x: lambda y: x
31+
FALSE = lambda x: lambda y: y
32+
33+
NOT = lambda p: p (FALSE) (TRUE)
34+
AND = lambda p: lambda q: p (q) (FALSE)
35+
OR = lambda p: lambda q: p (TRUE) (q)
36+
XOR = lambda p: lambda q: p (NOT (q)) (q)
37+
38+
# Tuples
39+
# ======
40+
41+
# Instantiate a 2-tuple by feeding 'TUPLE' with two elements. 'f' then allows
42+
# to retrieve the elements without 'b' applying to 'a'.
43+
TUPLE = lambda a: lambda b: lambda f: f (a) (b)
44+
_1ST = lambda t: t (FALSE)
45+
_2ND = lambda t: t (TRUE)
46+
47+
# Integers
48+
# ========
49+
# See https://en.wikipedia.org/wiki/Church_encoding#Calculation_with_Church_numerals
50+
51+
# SUCC(n) = n+1
52+
SUCC = lambda n: lambda f: lambda x: f (n (f) (x))
53+
# PREC(n) = n-1
54+
PREC = lambda n: lambda f: lambda x: (n
55+
(lambda g: lambda h: h (g (f)))
56+
(lambda u: x)
57+
(ID))
58+
59+
ADD = lambda m: lambda n: n (SUCC) (m)
60+
SUB = lambda m: lambda n: n (PREC) (m)
61+
TIMES = lambda m: lambda n: n (PLUS (n))
62+
63+
ZERO = FALSE
64+
ONE = SUCC (ZERO)
65+
TWO = SUCC (ONE)
66+
THREE = SUCC (TWO)
67+
68+
# IS_ZERO(n) = n == 0
69+
IS_ZERO = lambda n: n (lambda x: FALSE) (TRUE)
70+
# LEQ(n,m) = n <= m
71+
LEQ = lambda m: lambda n: IS_ZERO (SUB (m) (n))
72+
# EQ(n,m) = n ==m
73+
EQ = lambda m: lambda n: AND (LEQ (m) (n)) (LEQ (n) (m))
74+
75+
# Lambda terms
76+
# ============
77+
78+
ENUM_3_1 = lambda a: lambda b: lambda c: a
79+
ENUM_3_2 = lambda a: lambda b: lambda c: b
80+
ENUM_3_3 = lambda a: lambda b: lambda b: c
81+
82+
LAMBDA_VARIABLE_BUILDER = lambda n: TUPLE (ENUM_3_1) (n)
83+
LAMBDA_ABSTRACTION_BUILDER = lambda t: TUPLE (ENUM_3_2) (t)
84+
LAMBDA_APPLICATION_BUILDER = lambda x: lambda y: TUPLE (ENUM_3_3) (TUPLE (x) (y))
85+
86+
# Lambda lazy reduction
87+
# =====================
88+
89+
90+
# The arguments are:
91+
# f a self-reference dummy function for the Y combinator.
92+
# e the lambda term to reduce.
93+
# x the lambda term which the current expression is bound to.
94+
# n the current De Bruijn index.
95+
# Illegal lambda terms will cause undefined behavior.
96+
REDUCE = Y (lambda f: lambda e: lambda x: lambda n: _1ST (e)
97+
# If the variable is bound to 'x', then we replace; if not, we leave it
98+
# there.
99+
(lambda g: LAMBDA_VARIABLE_BUILDER
100+
(EQ (n) (_2ND (e))
101+
(x)
102+
(_2ND (e)))
103+
# We increment the counter 'n' and keep searching for terms bound to 'x'.
104+
(lambda g: LAMBDA_ABSTRACTION_BUILDER
105+
(f (_2ND (e)) (x) (SUCC (n))))
106+
(lambda g: LAMBDA_APPLICATION_BUILDER
107+
# We reduce both terms and then the second is applied to the first.
108+
(f (_1ST (_2ND (e))) (x) (n))
109+
# The dummy argument g=ID is just to avoid strict evaluation.
110+
(f (_2ND (_2ND (e))) (x) (n)))) (ID))
111+
112+
APPLY = Y (lambda f: lambda e: _1ST (e)
113+
# We only reduce applications.
114+
(LAMBDA_VARIABLE_BUILDER (_2ND (e)))
115+
(LAMBDA_ABSTRACTION_BUILDER (_2ND (e)))
116+
(REDUCE (_1ST (e)) (_2ND (e)) (ONE)))
117+
118+
# TODO APPLY
119+
"""
120+
BINARY_LAMBDA = lambda p: p (
121+
# p == 1
122+
(lambda p1: Y_COMBINATOR (lambda f: lambda n:))
123+
# p == 0
124+
(lambda p1: p1
125+
# pq == 01
126+
(lambda p2:)
127+
# pq == 00
128+
)
129+
)"""

0 commit comments

Comments
 (0)