lambda_calculus/data/num/
scott.rs

1//! [Scott numerals](http://lucacardelli.name/Papers/Notes/scott2.pdf)
2
3use crate::combinators::Z;
4use crate::data::boolean::{fls, tru};
5use crate::term::Term::*;
6use crate::term::{abs, app, Term};
7
8/// Produces a Scott-encoded number zero; equivalent to `boolean::tru`.
9///
10/// ZERO ≡ λxy.x ≡ λ λ 2 ≡ TRUE
11///
12/// # Example
13/// ```
14/// use lambda_calculus::data::num::scott::zero;
15/// use lambda_calculus::*;
16///
17/// assert_eq!(zero(), 0.into_scott());
18/// ```
19pub fn zero() -> Term {
20    tru()
21}
22
23/// Applied to a Scott-encoded number it produces a lambda-encoded boolean, indicating whether its
24/// argument is equal to zero.
25///
26/// IS_ZERO ≡ λn.n TRUE (λx.FALSE) ≡ λ 1 TRUE (λ FALSE)
27///
28/// # Example
29/// ```
30/// use lambda_calculus::data::num::scott::is_zero;
31/// use lambda_calculus::data::boolean::{tru, fls};
32/// use lambda_calculus::*;
33///
34/// assert_eq!(beta(app(is_zero(), 0.into_scott()), NOR, 0), tru());
35/// assert_eq!(beta(app(is_zero(), 1.into_scott()), NOR, 0), fls());
36/// ```
37pub fn is_zero() -> Term {
38    abs(app!(Var(1), tru(), abs(fls())))
39}
40
41/// Produces a Scott-encoded number one.
42///
43/// ONE ≡ λab.b ZERO ≡ λ λ 1 ZERO
44///
45/// # Example
46/// ```
47/// use lambda_calculus::data::num::scott::one;
48/// use lambda_calculus::*;
49///
50/// assert_eq!(one(), 1.into_scott());
51/// ```
52pub fn one() -> Term {
53    abs!(2, app(Var(1), zero()))
54}
55
56/// Applied to a Scott-encoded number it produces its successor.
57///
58/// SUCC ≡ λnxy.y n ≡ λ λ λ 1 3
59///
60/// # Example
61/// ```
62/// use lambda_calculus::data::num::scott::succ;
63/// use lambda_calculus::*;
64///
65/// assert_eq!(beta(app(succ(), 0.into_scott()), NOR, 0), 1.into_scott());
66/// assert_eq!(beta(app(succ(), 1.into_scott()), NOR, 0), 2.into_scott());
67/// ```
68pub fn succ() -> Term {
69    abs!(3, app(Var(1), Var(3)))
70}
71
72/// Applied to a Scott-encoded number it produces its predecessor.
73///
74/// PRED ≡ λn.n ZERO (λx.x) ≡ λ 1 ZERO (λ 1)
75///
76/// # Example
77/// ```
78/// use lambda_calculus::data::num::scott::pred;
79/// use lambda_calculus::*;
80///
81/// assert_eq!(beta(app(pred(), 1.into_scott()), NOR, 0), 0.into_scott());
82/// assert_eq!(beta(app(pred(), 3.into_scott()), NOR, 0), 2.into_scott());
83/// ```
84pub fn pred() -> Term {
85    abs(app!(Var(1), zero(), abs(Var(1))))
86}
87
88/// Applied to two Scott-encoded numbers it produces their sum.
89///
90/// ADD ≡ Z (λfmn.m n (λo. SUCC (f o n))) ≡ Z (λ λ λ 2 1 (λ SUCC (4 1 2)))
91///
92/// # Example
93/// ```
94/// use lambda_calculus::data::num::scott::add;
95/// use lambda_calculus::*;
96///
97/// assert_eq!(beta(app!(add(), 1.into_scott(), 2.into_scott()), NOR, 0), 3.into_scott());
98/// assert_eq!(beta(app!(add(), 2.into_scott(), 3.into_scott()), NOR, 0), 5.into_scott());
99/// ```
100/// # Errors
101///
102/// This function will overflow the stack if used with an applicative-family (`APP` or `HAP`)
103/// reduction order.
104pub fn add() -> Term {
105    app(
106        Z(),
107        abs!(
108            3,
109            app!(
110                Var(2),
111                Var(1),
112                abs(app(succ(), app!(Var(4), Var(1), Var(2))))
113            )
114        ),
115    )
116}
117/*
118/// Applied to two Scott-encoded numbers it subtracts the second one from the first one.
119///
120/// SUB ≡
121///
122/// # Example
123/// ```
124/// use lambda_calculus::data::num::scott::sub;
125/// use lambda_calculus::*;
126///
127/// assert_eq!(beta(app!(sub(), 1.into_scott(), 0.into_scott()), NOR, 0), 1.into_scott());
128/// assert_eq!(beta(app!(sub(), 3.into_scott(), 1.into_scott()), NOR, 0), 2.into_scott());
129/// assert_eq!(beta(app!(sub(), 5.into_scott(), 2.into_scott()), NOR, 0), 3.into_scott());
130/// ```
131pub fn sub() -> Term {
132
133}
134*/
135/// Applied to two Scott-encoded numbers it yields their product.
136///
137/// MUL ≡ Z (λfmn.m ZERO (λo. ADD n (f o n))) ≡ Z (λ λ λ 2 ZERO (λ ADD 2 (4 1 2)))
138///
139/// # Example
140/// ```
141/// use lambda_calculus::data::num::scott::mul;
142/// use lambda_calculus::*;
143///
144/// assert_eq!(beta(app!(mul(), 1.into_scott(), 2.into_scott()), NOR, 0), 2.into_scott());
145/// assert_eq!(beta(app!(mul(), 2.into_scott(), 3.into_scott()), NOR, 0), 6.into_scott());
146/// ```
147/// # Errors
148///
149/// This function will overflow the stack if used with an applicative-family (`APP` or `HAP`)
150/// reduction order.
151pub fn mul() -> Term {
152    app(
153        Z(),
154        abs!(
155            3,
156            app!(
157                Var(2),
158                zero(),
159                abs(app!(add(), Var(2), app!(Var(4), Var(1), Var(2))))
160            )
161        ),
162    )
163}
164
165/// Applied to two Scott-encoded numbers it raises the first one to the power of the second one.
166///
167/// POW ≡ Z (λfmn.n ONE (λo. MUL m (f m o))) ≡ Z (λ λ λ 1 ONE (λ MUL 3 (4 3 1)))
168///
169/// # Example
170/// ```
171/// use lambda_calculus::data::num::scott::pow;
172/// use lambda_calculus::*;
173///
174/// assert_eq!(beta(app!(pow(), 1.into_scott(), 2.into_scott()), NOR, 0), 1.into_scott());
175/// assert_eq!(beta(app!(pow(), 2.into_scott(), 3.into_scott()), NOR, 0), 8.into_scott());
176/// ```
177/// # Errors
178///
179/// This function will overflow the stack if used with an applicative-family (`APP` or `HAP`)
180/// reduction order.
181pub fn pow() -> Term {
182    app(
183        Z(),
184        abs!(
185            3,
186            app!(
187                Var(1),
188                one(),
189                abs(app!(mul(), Var(3), app!(Var(4), Var(3), Var(1))))
190            )
191        ),
192    )
193}
194
195/// Applied to a Scott-encoded number it produces the equivalent Church-encoded number.
196///
197/// TO_CHURCH ≡ λabc.Z (λdefg.g f (λh.e (d e f h))) b c a
198///           ≡ λ λ λ Z (λ λ λ λ 1 2 (λ 4 (5 4 3 1))) 2 1 3
199///
200/// # Example
201/// ```
202/// use lambda_calculus::data::num::scott::to_church;
203/// use lambda_calculus::*;
204///
205/// assert_eq!(beta(app(to_church(), 0.into_scott()), NOR, 0), 0.into_church());
206/// assert_eq!(beta(app(to_church(), 1.into_scott()), NOR, 0), 1.into_church());
207/// assert_eq!(beta(app(to_church(), 2.into_scott()), NOR, 0), 2.into_church());
208/// ```
209/// # Errors
210///
211/// This function will overflow the stack if used with an applicative-family (`APP` or `HAP`)
212/// reduction order.
213pub fn to_church() -> Term {
214    abs!(
215        3,
216        app!(
217            Z(),
218            abs!(
219                4,
220                app!(
221                    Var(1),
222                    Var(2),
223                    abs(app(Var(4), app!(Var(5), Var(4), Var(3), Var(1))))
224                )
225            ),
226            Var(2),
227            Var(1),
228            Var(3)
229        )
230    )
231}