COMBINATORS
COMBINATORS
Inspired by :
https://www.youtube.com/watch?
v=6BnVo7EHO_8&t=453s&ab_channel=SmartlyIOEngineering (Part 1)
https://www.youtube.com/watch?v=pAnLQ9jwN-E&t=1215s (Part 2)
https://www.youtube.com/watch?
v=gnrSedVucXs&t=1545s&ab_channel=MaltaMathematicalSociety
_Combinators_
https://www.angelfire.com/tx4/cus/combinator/birds.html
S :S : Labc.ac(bc) : Starling
K :K : Lab.a : Kesrel (true, first, const)
I : SKK : La.a : Idiot (identity)
(KI) : KI = CK : Lab.b : Kite (false, second, zero)
B : S(KS)k : Labc.a(bc) : Bluebird (function composition)
B1 : BBB : Labcd.a(bcd) : Blackbird (function composition)
C : S(BBS)(KK) : Labc.acb : Cardinal
T : CI : Lab.ba : Trush
M : SII : La.aa : Mockingbird
V : BCT : Labc.cab : Viereo (Pairing)
_Boolean Combinator_
DEFINITIONS :
⁃ Constant value :
[true] = K : [true]xy -> x
[false] = KI : [false]xy -> y
⁃ Unary fonction :
[not] = C : [not]pxy -> pyx or [not]p -> p[false][true]
⁃ Binary functions :
[or] = M* : [or]pq -> ppq or, [or]pq -> p[true]q
[and] : [and]pq -> pqp or, [and]pq -> pq[false]
[eq] : [eq]pq -> pq([not]q)
[nor] : [nor]pq -> p([not]p)([not]q) or, [or]pq -> p[false]([not]q)
[nand] : [nand]pq -> p([not]q)([not]p) or, [nand]pq -> p([not]q)[true]
[xor] : [xor]pq -> p([not]q)q
[->] : [->]pq -> pq([not]p) or, [->]pq -> pq[true]
[<-] : [<-]pq -> qp([not]q) or, [<-]pq -> qp[true]
[/>] : [/>]pq -> p([not]q)p or, [/>]pq -> p([not]q)[false]
[<\] : [<\]pq -> q([not]p)q or, [<\]pq -> q([not]p)[false]
With [or] and [not], that is C and M*, as we know, it is possible to define all others boolean
operators. I've defined to most used and interisting ones. The six combinators left are the
most trivial ones i.e. those that returns p, q, not-p, not-q, constant-true and constant-false.
note that the combinators that returns p and q are K and KI respectively.
EXEMPLES :
[eq]([not]([and]pq))([or]([not]p)([not]q))
-> [eq]([not](pqp))([or]([not]p)([not]q))
-> [eq]([not](pqp))([not]p([not]p)([not]q))
-> [eq]([not](pqp))(p([not]q)([not]p))
-> [not](pqp)(p([not]q)([not]p))([not](p([not]q)([not]p)))
-> (pqp)([not](p([not]q)([not]p)))(p([not]q)([not]p)) (1)
If p = [true] and q = [true], then, (pqp) reduces to [true] and (p([not]q)([not]p)) reduces to
[false], so (1) gives :
-> [true]([not][false])[false] -> [true]
If p = [true] and q = [false], (pqp) reduces to [false] and (p([not]q)([not]p)) reduces to [true],
so (1) gives :
-> [false]([not][true])[true] -> [true]
If p = [false] and q = [true], (pqp) reduces to [false] and (p([not]q)([not]p)) reduces to [true],
so (1) gives :
-> [false]([not][true])[true] -> [true]
If p = [false] and q = [false], then, (pqp) reduces to [false] and (p([not]q)([not]p)) reduces to
[true], so (1) gives :
-> [false]([not][true])[true] -> [true]
QED !
When p = [false] we can see that the value of (pqp) and (p([not]q)([not]p)) do not depends
on q, so, when p = [false], it is unecessary to check for both value of q.
[->]([AND]p([->]pq))q
-> [->](p([->]pq)p)q
-> [->](p(pq([not]p))p)q
-> (p(pq([not]p))p)q([not](p(pq([not]p))p)) (1)
QED !
The expression (1) is the reduction of an implication and is of the form ab([not]a) with a =
(p(pq([not]p))p) and b = q. Therefore, (1) will always reduce to [true] when a = [False] (as
expected, an implication is true whenever its antecedent is false) and a (of the form cdc with
c = p and d = (pq([not]p)) will always reduce to [false] when p = [false]. Therefore, it is
only necessary to check for q = [true] and q = [false] when p = [true].
_ℕ Arithmetic Combinator_
DEFINITIONS :
_ Pairs :
[pair] = V : [pair]xyf -> fxy
[fst] = TK : [fst]p -> pK
[snd] = T(KI) : [snd]p -> p(KI)
_Operators :
[succ] = SB : [succ]nfa -> f(nfa) or, [succ]nf -> Bf(nf)
[+] : [+]nk -> n[succ]k or, [+]nkf->B(nf)(kf)
[*] = B : [*]nkf -> n(kf)
[^] = T : [^]nk -> kn
[pred] : [pred]n -> [fst](n[phi]([pair][0][0])) (note : [pred][0] = [0])
With [phi] : [phi]p -> [pair]([snd]p)([succ]([snd]p))
[-] : [-]nk -> k[pred]n (note : if k≤n then [-]nk = [0])
_Predicates :
[is0] : [is0]n -> n(K[false])[true]
[=<] : [=<]nk -> [is0]([-]nk)
[=] : [=]nk -> [and]([=<]nk)([=<]kn)
[>] = B1KI[=<] : [>]nk -> [not]([=<]nk)
EXEMPLE :
[*]([^][2][2])[2]
-> [*]([2][2])[2]
To prove that this expression is extensionally equal to [8], we feed it with argument fx and
check that it reduces to f(f(f(f(f(f(f(fx))))))).
-> [*]([2][2])[2]fx
-> [2][2]([2]f)x
-> [2]([2]([2]f))x
-> [2]([2]f)([2]([2]f)x)
-> [2]([2]f)([2]f([2]fx))
-> [2]([2]f)([2]f(f(fx)))
-> [2]([2]f)(f(f(f(fx))))
-> [2]f([2]f(f(f(f(fx)))))
-> [2]f(f(f(f(f(f(fx))))))
-> f(f(f(f(f(f(f(fx)))))))
For reading the value of [n] as a "human" number when implementing in a programming
langage, we use f = (x -> x+1) and x = 0. Then, [n]fx will return n in the programming
language.
• The falsity of 2≤1 reduction :
[=<][2][1]
-> [is0]([-][2][1])
-> [is0]([1][pred][2])
-> [is0]([pred][2])
-> [is0]([fst]([2][phi]([pair][0][0])))
-> [is0]([fst]([phi]([phi]([pair][0][0]))))
-> [is0]([fst]([phi]([pair]([snd]([pair][0][0]))([succ]([snd]([pair][0][0]))))))
-> [is0]([fst]([phi]([pair]([pair][0][0](KI))([succ]([snd]([pair][0][0]))))))
-> [is0]([fst]([phi]([pair]((KI)[0][0])([succ]([snd]([pair][0][0]))))))
-> [is0]([fst]([phi]([pair][0]([succ]([snd]([pair][0][0]))))))
-> [is0]([fst]([phi]([pair][0]([succ]([pair][0][0](KI))))))
-> [is0]([fst]([phi]([pair][0]([succ]((KI)[0][0])))))
-> [is0]([fst]([phi]([pair][0]([succ][0]))))
([succ][0] = [1] by definition of [n]. We can check that [succ][0] is extensionally equal to [1]
by feeding it fx argument and checking that it reduces to fx.)
= [is0]([fst]([phi]([pair][0][1])))
-> [is0]([fst]([pair]([snd]([pair][0][1]))([succ]([snd]([pair][0][1])))))
-> [is0]([fst]([pair]([pair][0][1](KI))([succ]([snd]([pair][0][1])))))
-> [is0]([fst]([pair]((KI)[0][1])([succ]([snd]([pair][0][1])))))
-> [is0]([fst]([pair][1]([succ]([snd]([pair][0][1])))))
Because we're calling the first element of the pair, we don't need to reduce the second, that
is : [succ]([snd]([pair][0][1]))
-> [is0]([pair][1]([succ]([snd]([pair][0][1])))K)
-> [is0](K[1]([succ]([snd]([pair][0][1]))))
-> [is0][1]
-> [1](K[false])[true]
-> K[false][true] -> [false]
We see that for an addition or a subtraction by n, we need to apply [succ] or [pred] n times on
k and for [pred] of k, we need to apply [phi] k times.
_Fibonacci Programme_
Return the nth number of the fibonacci sequence.
https://www.analyticsvidhya.com/blog/2023/09/fibonacci-series-in-python/
DEFINITIONS :
• Pseudo-code :
• Combinator fib(n) :
EXEMPLES :
[fib1][3]
-> [is0][3][0]([=<][3][2][1]([+]([fib]([-][3][1]))([fib]([-][3][2]))))
-> [3](K[false])[true][0]([=<][3][2][1]([+]([fib]([-][3][1]))([fib]([-][3][2]))))
-> K[false](K[false]((K[false])[true]))[0]([=<][3][2][1]([+]([fib]([-][3][1]))([fib]([-][3]
[2]))))
-> [false][0]([=<][3][2][1]([+]([fib]([-][3][1]))([fib]([-][3][2]))))
Now that we know that 3 ≠ 0, we can check if 3 ≤ 2.
-> [=<][3][2][1]([+]([fib1]([-][3][1]))([fib1]([-][3][2])))
-> [is0]([-][3][2])[1]([+]([fib1]([-][3][1]))([fib1]([-][3][2])))
-> [is0]([2][pred][3])[1]([+]([fib1]([-][3][1]))([fib1]([-][3][2])))
-> [is0]([pred]([pred][3]))[1]([+]([fib1]([-][3][1]))([fib1]([-][3][2])))
-> [is0]([pred]([fst]([3][phi]([pair][0][0]))))[1]([+]([fib1]([-][3][1]))([fib1]([-][3][2])))
-> [is0]([pred]([fst]([phi]([phi]([phi]([pair][0][0]))))))[1]([+]([fib1]([-][3][1]))([fib1]
([-][3][2])))
-> [is0]([pred]([fst]([phi]([phi]([pair]([snd]([pair][0][0]))([succ]([snd]([pair][0]
[0]))))))))[1]([+]([fib1]([-][3][1]))([fib1]([-][3][2])))
-> [is0]([pred]([fst]([phi]([phi]([pair]([pair][0][0](KI))([succ]([snd]([pair][0][0]))))))))
[1]([+]([fib1]([-][3][1]))([fib]([-][3][2])))
-> [is0]([pred]([fst]([phi]([phi]([pair]((KI)[0][0])([succ]([snd]([pair][0][0]))))))))[1]
([+]([fib1]([-][3][1]))([fib1]([-][3][2])))
-> [is0]([pred]([fst]([phi]([phi]([pair][0]([succ]([snd]([pair][0][0]))))))))[1]([+]([fib1]
([-][3][1]))([fib1]([-][3][2])))
-> [is0]([pred]([fst]([phi]([phi]([pair][0]([succ]([pair][0][0](KI))))))))[1]([+]([fib]([-]
[3][1]))([fib1]([-][3][2])))
-> [is0]([pred]([fst]([phi]([phi]([pair][0]([succ]((KI)[0][0])))))))[1]([+]([fib1]([-][3]
[1]))([fib1]([-][3][2])))
-> [is0]([pred]([fst]([phi]([phi]([pair][0]([succ][0]))))))[1]([+]([fib1]([-][3][1]))([fib1]
([-][3][2])))
([succ][0] = [1] by definition of [n]. We can check that [succ][0] is extensionally equal to [1]
by feeding it fx argument and checking that it reduces to fx.)
We need to derive [phi]p two times more like above.
= [is0]([pred]([fst]([phi]([phi]([pair][0][1])))))[1]([+]([fib1]([-][3][1]))([fib1]([-][3]
[2])))
-> [is0]([pred]([fst]([phi]([pair]([snd]([pair][0][1]))([succ]([snd]([pair][0][1])))))))[1]
([+]([fib1]([-][3][1]))([fib1]([-][3][2])))
-> [is0]([pred]([fst]([phi]([pair]([pair][0][1](KI))([succ]([snd]([pair][0][1])))))))[1]([+]
([fib1]([-][3][1]))([fib1]([-][3][2])))
-> [is0]([pred]([fst]([phi]([pair]((KI)[0][1])([succ]([snd]([pair][0][1])))))))[1]([+]
([fib1]([-][3][1]))([fib1]([-][3][2])))
-> [is0]([pred]([fst]([phi]([pair][1]([succ]([snd]([pair][0][1])))))))[1]([+]([fib1]([-][3]
[1]))([fib1]([-][3][2])))
-> [is0]([pred]([fst]([phi]([pair][1]([succ]([pair][0][1](KI)))))))[1]([+]([fib1]([-][3]
[1]))([fib1]([-][3][2])))
-> [is0]([pred]([fst]([phi]([pair][1]([succ]((KI)[0][1]))))))[1]([+]([fib1]([-][3][1]))
([fib1]([-][3][2])))
-> [is0]([pred]([fst]([phi]([pair][1]([succ][1])))))[1]([+]([fib1]([-][3][1]))([fib1]([-][3]
[2])))
([succ][1] = [2] by definition of [n]. We can check that [succ][1] is extensionally equal to [2]
by feeding it fx argument and checking that it reduces to f(fx).)
= [is0]([pred]([fst]([phi]([pair][1][2]))))[1]([+]([fib1]([-][3][1]))([fib1]([-][3][2])))
-> [is0]([pred]([fst]([pair]([snd]([pair][1][2]))([succ]([snd]([pair][1][2]))))))[1]([+]
([fib1]([-][3][1]))([fib1]([-][3][2])))
-> [is0]([pred]([fst]([pair]([pair][1][2](KI))([succ]([snd]([pair][1][2]))))))[1]([+]([fib1]
([-][3][1]))([fib]1([-][3][2])))
-> [is0]([pred]([fst]([pair]((KI)[1][2])([succ]([snd]([pair][1][2]))))))[1]([+]([fib1]([-]
[3][1]))([fib1]([-][3][2])))
-> [is0]([pred]([fst]([pair][2]([succ]([snd]([pair][1][2]))))))[1]([+]([fib1]([-][3][1]))
([fib1]([-][3][2])))
Because we're calling the first element of the pair, we don't need to reduce the second, that
is : [succ]([snd]([pair][1][2]))
-> [is0]([pred]([pair][2]([succ]([snd]([pair][1][2])))K))[1]([+]([fib1]([-][3][1]))([fib1]
([-][3][2])))
-> [is0]([pred](K[2]([succ]([snd]([pair][1][2])))))[1]([+]([fib1]([-][3][1]))([fib1]([-][3]
[2])))
-> [is0]([pred][2])[1]([+]([fib1]([-][3][1]))([fib1]([-][3][2])))
To finish the reduction of [-][3][2] above, we know need to reduce the second iteration of
[pred] on [2] that we just get. It is exactly analogous as above with one less application of
[phi]. It was donne in details in the previous exemple, we therefore jump straight to the result.
... ... ...
-> [is0][1][1]([+]([fib1]([-][3][1]))([fib1]([-][3][2])))
-> [1](K[false])[true][1]([+]([fib1]([-][3][1]))([fib1]([-][3][2])))
-> K[false][true][1]([+]([fib1]([-][3][1]))([fib1]([-][3][2])))
-> [false][1]([+]([fib]([-][3][1]))([fib]([-][3][2])))
Now that we know that 3 ≰ 2, we can apply the function recursively to compute the 3rd
fibonacci number.
-> [+]([fib1]([-][3][1]))([fib1]([-][3][2]))
-> [+]([fib1]([1][pred][3]))([fib1]([-][3][2]))
-> [+]([fib1]([pred][3]))([fib1]([-][3][2]))
We reduce [pred][3] exactly as above.
... ... ...
-> [+]([fib1][2])([fib1]([-][3][2]))
We reduce [-][3][2] exactly as above.
... ... ...
-> [+]([fib1][2])([fib1][1])
-> [+]([is0][2][0]([=<][2][2][1]([+]([fib1]([-][2][1]))([fib1]([-][2][2])))))([fib1][1])
-> [+]([2](K[false])[true][0]([=<][2][2][1]([+]([fib1]([-][2][1]))([fib1]([-][2][2])))))
([fib1][1])
-> [+](K[false]((K[false])[true])[0]([=<][2][2][1]([+]([fib1]([-][2][1]))([fib1]([-][2]
[2])))))([fib1][1])
-> [+]([false][0]([=<][2][2][1]([+]([fib1]([-][2][1]))([fib1]([-][2][2])))))([fib1][1])
-> [+]([=<][2][2][1]([+]([fib1]([-][2][1]))([fib1]([-][2][2]))))([fib1][1])
-> [+]([is0]([-][2][2])[1]([+]([fib1]([-][2][1]))([fib1]([-][2][2]))))([fib1][1])
-> [+]([is0]([2][pred][2])[1]([+]([fib1]([-][2][1]))([fib1]([-][2][2]))))([fib]1[1])
-> [+]([is0]([pred]([pred][2]))[1]([+]([fib1]([-][2][1]))([fib1]([-][2][2]))))([fib1][1])
We reduce [pred][2] as previous exemple.
... ... ...
-> [+]([is0]([pred][1]) [1]([+]([fib1]([-][2][1]))([fib1]([-][2][2]))))([fib][1])
-> [+]([is0]([fst]([1][phi]([pair][0][0])))[1]([+]([fib1]([-][2][1]))([fib1]([-][2][2]))))
([fib][1])
-> [+]([is0]([fst]([phi]([pair][0][0])))[1]([+]([fib1]([-][2][1]))([fib1]([-][2][2]))))([fib]
[1])
-> [+]([is0]([fst]([pair]([snd]([pair][0][0]))([succ]([snd]([pair][0][0])))))[1]([+]([fib1]
([-][2][1]))([fib1]([-][2][2]))))([fib][1])
-> [+]([is0]([fst]([pair]([pair][0][0](KI))([succ]([snd]([pair][0][0])))))[1]([+]([fib1]([-]
[2][1]))([fib1]([-][2][2]))))([fib][1])
-> [+]([is0]([fst]([pair]((KI)[0][0])([succ]([snd]([pair][0][0])))))[1]([+]([fib1]([-][2]
[1]))([fib1]([-][2][2]))) )([fib][1])
-> [+]([is0]([fst]([pair][0]([succ]([snd]([pair][0][0])))))[1]([+]([fib1]([-][2][1]))([fib1]
([-][2][2]))))([fib][1])
Because we're calling the first element of the pair, we don't need to reduce the second, that
is : [succ]([snd]([pair][0][0]))
-> [+]([is0]([pair][0]([succ]([snd]([pair][0][0])))K)[1]([+]([fib1]([-][2][1]))([fib1]([-]
[2][2]))))([fib][1])
-> [+]([is0](K[0]([succ]([snd]([pair][0][0]))))[1]([+]([fib1]([-][2][1]))([fib1]([-][2]
[2]))))([fib][1])
-> [+]([is0][0][1]([+]([fib1]([-][2][1]))([fib1]([-][2][2]))))([fib][1])
-> [+]([0](K[false])[true][1]([+]([fib1]([-][2][1]))([fib1]([-][2][2]))))([fib1][1])
-> [+]([true][1]([+]([fib1]([-][2][1]))([fib1]([-][2][2]))))([fib1][1])
-> [+][1]([fib1][1])
-> [+][1]([is0][1][0]([=<][1][2][1]([+]([fib1]([-][1][1]))([fib1]([-][1][2])))))
-> [+][1]([1](K[false])[true][0]([=<][1][2][1]([+]([fib1]([-][1][1]))([fib1]([-][1][2])))))
-> [+][1](K[false][true][0]([=<][1][2][1]([+]([fib1]([-][1][1]))([fib1]([-][1][2])))))
-> [+][1]([false][0]([=<][1][2][1]([+]([fib1]([-][1][1]))([fib1]([-][1][2])))))
-> [+][1]([=<][1][2][1]([+]([fib1]([-][1][1]))([fib1]([-][1][2]))))
-> [+][1]([is0]([-][1][2])[1]([+]([fib1]([-][1][1]))([fib1]([-][1][2]))))
-> [+][1]([is0]([2][pred][2])[1]([+]([fib1]([-][1][1]))([fib1]([-][1][2]))))
-> [+][1]([is0]([pred]([pred][2]))[1]([+]([fib1]([-][1][1]))([fib1]([-][1][2]))))
We reduce [pred][2] as previous exemple.
-> [+][1]([is0]([pred][1])[1]([+]([fib1]([-][1][1]))([fib1]([-][1][2]))))
We reduce [pred][1] as previous above.
-> [+][1]([is0][0][1]([+]([fib1]([-][1][1]))([fib1]([-][1][2]))))
-> [+][1]([0](K[false])[true][1]([+]([fib1]([-][1][1]))([fib1]([-][1][2]))))
-> [+][1]([true][1]([+]([fib1]([-][1][1]))([fib1]([-][1][2]))))
-> [+][1][1]
-> [1][succ][1] -> [succ][1] = [2]
The function [-] is horrible to reduce. [fib1] is full of [-] in [is0], [=<] and with the recursion,
which makes it a pain to reduce.
[fib2][3]
-> [fst]([3][next]([pair][0][1]))
-> [fst]([next]([next]([next]([pair][0][1]))))
-> [fst]([next]([next]([pair]([snd]([pair][0][1]))([+]([fst]([pair][0][1]))([snd]([pair][0]
[1]))))))
-> [fst]([next]([next]([pair]([snd]([pair][0][1]))([+]([fst]([pair][0][1]))([pair][0][1]
(KI))))))
-> [fst]([next]([next]([pair]([snd]([pair][0][1]))([+]([fst]([pair][0][1]))((KI)[0][1])))))
-> [fst]([next]([next]([pair]([snd]([pair][0][1]))([+]([fst]([pair][0][1]))[1]))))
-> [fst]([next]([next]([pair]([snd]([pair][0][1]))([+]([pair][0][1]K)[1]))))
-> [fst]([next]([next]([pair]([snd]([pair][0][1]))([+](K[0][1])[1]))))
-> [fst]([next]([next]([pair]([snd]([pair][0][1]))([+][0][1]))))
-> [fst]([next]([next]([pair]([snd]([pair][0][1]))([0][succ][1]))))
-> [fst]([next]([next]([pair]([snd]([pair][0][1]))[1])))
-> [fst]([next]([next]([pair]([pair][0][1](KI))[1])))
-> [fst]([next]([next]([pair]((KI)[0][1])[1])))
-> [fst]([next]([next]([pair][1][1])))
-> [fst]([next]([pair]([snd]([pair][1][1]))([+]([fst]([pair][1][1]))([snd]([pair][1][1])))))
-> [fst]([next]([pair]([snd]([pair][1][1]))([+]([fst]([pair][1][1]))([pair][1][1](KI)))))
-> [fst]([next]([pair]([snd]([pair][1][1]))([+]([fst]([pair][1][2]))((KI)[1][1]))))
-> [fst]([next]([pair]([snd]([pair][1][1]))([+]([fst]([pair][1][1]))[1])))
-> [fst]([next]([pair]([snd]([pair][1][1]))([+]([pair][1][1]K)[1])))
-> [fst]([next]([pair]([snd]([pair][1][1]))([+](K[1][1])[1])))
-> [fst]([next]([pair]([snd]([pair][1][1]))([+][1][1])))
-> [fst]([next]([pair]([snd]([pair][1][1]))([1][succ][1])))
-> [fst]([next]([pair]([snd]([pair][1][1]))([succ][1])))
= [fst]([next]([pair]([snd]([pair][1][1]))[2])) (for [succ][1] = [2])
-> [fst]([next]([pair]([pair][1][1](KI))[2]))
-> [fst]([next]([pair]((KI)[1][1])[2]))
-> [fst]([next]([pair][1][2]))
-> [fst]([next]([pair][1][2]))
-> [fst]([pair]([snd]([pair][1][2]))([+]([fst]([pair][1][2]))([snd]([pair][1][2]))))
Because we will call the first element of the main pair, we don't need to reduce the second,
that is : [+]([fst]([pair][2][3]))([snd]([pair][2][3]))
-> [fst]([pair]([pair][1][2](KI))([+]([fst]([pair][1][2]))([snd]([pair][1][2]))))
-> [fst]([pair]((KI)[1][2])([+]([fst]([pair][1][2]))([snd]([pair][1][2]))))
-> [fst]([pair][2]([+]([fst]([pair][1][2]))([snd]([pair][1][2]))))
-> [pair][2]([+]([fst]([pair][1][2]))([snd]([pair][1][2])))K
-> K[2]([+]([fst]([pair][1][2]))([snd]([pair][1][2]))) -> [2]
_JavaScript Implementation_
_To try out combinators without calculating by hand, copy paste in here :
https://jipsen.github.io/js.html
// boolean :
T = a => b => a
F = a => b => b
NOT = a => a(F)(T)
AND = a => b => a(b)(a)
OR = a => b => a(a)(b)
EQ = a => b => a(b)(NOT(b))
IMP = a => b => a(b)(NOT(a))
// exemples :
DM = a => b => EQ(NOT(AND(a)(b)))(OR(NOT(a))(NOT(b))) // DeMorgan's
MP = a => b => IMP(AND(a)(IMP(a)(b)))(b) // Modus Ponens
// arithmetic :
PAIR = a => b => c => c(a)(b) // create a pair.
FST = a => a(T) // first or left function, apply to a pair.
SND = a => a(F) // second or right function, apply to a pair.
n0 = F // church numeral 0
jsnum = a => a(x => x+1)(0) // to display human numerals.