Church encodings
Table of Contents
1. Review
We looked at Church encodings of four different data types:
- Booleans
- Natural numbers
- Pairs
- Lists
1.1. Booleans
Booleans can be one of two values, \(๐\) and \(๐ฝ\). In Haskell, they are
represented by the algebraic data type Bool
:
data Bool = True | False
In ฮป-calculus we can represent them as two ฮป-terms: \[๐ โ ฮปx, y.x\] \[๐ฝ โ ฮปx, y.y\] Defining Booleans this way allows us to define fun operations on Booleans, such as: \[\mathtt{ifThenElse} โ ฮปp, x, y.p\,x\,y\] \[\mathtt{not} โ ฮปp.p\,๐ฝ\,๐\] \[\mathtt{and} โ ฮปp, q.p\,q\,๐ฝ\] \[\mathtt{or} โ ฮปp, q.p\,๐\,q\]
1.2. Natural numbers
The natural numbers 0, 1, 2, etc., can be encoded in Haskell by the algebraic
data type Nat
:
data Nat = Zero | Succ Nat
In ฮป-calculus we can represent them by using the following translation (\(โยทโ\)): \[โ0โ โ ฮปs, z.z\] \[โ\mathtt{Succ}\,nโ โ ฮปs, z.s\,(โnโ\,s\,z)\] For example, \(1\) (i.e., \(\mathtt{Succ}\,0\)) would receive the translation \(โ\mathtt{Succ}\,0โ = ฮปs, z.s\,(โ0โ\,s\,z) = ฮปs, z.s\,((ฮปs, z.z)\,s\,z) โ_ฮฒ^* ฮปs, z.s\,(s\,z)\). In general, the number of occurrences of the variable bound by the outer abstraction in the encoding of a natural number is just that number.
We can now define functions on natural numbers, such as \[\mathtt{succ} โ ฮปn, s, z.s\,(n\,s\,z)\] i.e., the successor function, which, given a natural number, takes its successor. Other useful operations are \[\mathtt{plus} โ ฮปm, n.m\,\mathtt{succ}\,n\] which takes the successor of \(n\) \(m\) times, and \[\mathtt{mult} โ ฮปm, n.m\,(\mathtt{plus}\,n)\,โ0โ\] which adds \(n\) to \(0\) \(m\) times.
1.3. Pairing
Taking a pair of two values can be done as follows: \[โโจa, bโฉโ โ ฮปf.f\,โaโ\,โbโ\] Given this encoding of pairing, we may define the following two projection functions, which take the first and second projections of a pair, respectively: \[ฯโ โ ฮปp.p\,๐\] \[ฯโ โ ฮปp.p\,๐ฝ\] In Haskell, these functions correspond to the functions
fst :: (a, b) -> a snd :: (a, b) -> b
which give back the first and second projections of a pair, respectively.
1.4. Lists
Finally, lists! In Haskell, these are encoded as an algebraic data type (equivalent to)
data List a = Empty | Cons a (List a)
In the ฮป-calculus, we may define them as using the translation \[โ[]โ โ ฮปc, n.n\] \[โa : lโ โ ฮปc, n.c\,โaโ\,(โlโ\,c\,n)\] For example, the the list \([1]\) would be translated as \(โ[1]โ = ฮปc, n.c\,โ1โ(โ[]โ\,c\,n) = ฮปc, n.c\,โ1โ\,((ฮปc, n.n)\,c\,n) โ_ฮฒ^* ฮปc, n.c\,โ1โ\,n\).
We can now, e.g., take the length of a list in terms of a function \[\mathtt{length} โ ฮปl.l\,(ฮปx.\mathtt{succ})\,โ0โ\] and we can, e.g., take the head (i.e., first element) of a list using a function \[\mathtt{head} โ ฮปl.l\,๐\,๐ฝ\] Note that, if passed the empty list, \(\mathtt{head}\) just gives back \(๐ฝ\).
2. Exercises
2.1. Part 1
Compute \(\mathtt{plus}\,โ2โ\,โ3โ\).
2.2. Part 2
Define a function \(\mathtt{ifThen}\) which takes two truth values and gives back \(๐\) if the first truth value is \(๐ฝ\) or the second truth value is \(๐\) (or if both the first is \(๐ฝ\) and the second is \(๐\)). Do this without using either \(\mathtt{not}\) or \(\mathtt{or}\) in your definition!
2.3. Part 3
Define a function \(\mathtt{append}\) which takes two lists and appends them. That is, \(\mathtt{append}\) should have the following behavior: \[\mathtt{append}\,โ[]โ\,l โก_ฮฒ l\] \[\mathtt{append}\,โa : lโโ\,lโ โก_ฮฒ ฮปc, n.c\,โaโ\,(\mathtt{append}\,lโ\,lโ)\]
2.4. Part 4
Define a function \(\mathtt{all}\) which, given a list of Booleans (i.e., either \(๐\) or \(๐ฝ\)), returns \(๐\) if all of them are \(๐\) and returns \(๐ฝ\) otherwise.
2.5. Part 5
Define a function \(\mathtt{any}\) which, given a list of Booleans (i.e., either \(๐\) or \(๐ฝ\)), returns \(๐\) if any of them is \(๐\) and returns \(๐ฝ\) otherwise.
2.6. Part 6
Define a function \(\mathtt{sum}\) which, given a list of natural numbers, returns their sum.
2.7. Part 7
Define a function \(\mathtt{map}\) which, given a function \(f\) from \(a\)'s to \(b\)'s, applies \(f\) to each member of a list of \(a\)'s to get back a list of \(b\)'s. That is, \(\mathtt{map}\) should have the following behavior: \[\mathtt{map}\,f\,โ[]โ โก_ฮฒ โ[]โ\] \[\mathtt{map}\,f\,โa : lโ โก_ฮฒ ฮปc, n.c\,(f\,โaโ)\,(\mathtt{map}\,f\,โlโ\,c\,n)\]
2.8. Part 8
Define a function \(\mathtt{filter}\) which, given a function \(f\) from \(a\)'s to Booleans and a list of \(a\)'s, filters the list using \(f\). That is, it returns a new list of \(a\)'s such that \(x\) is on the new list just in case \(x\) was on the old list and \(f x โ_ฮฒ^* ๐\). In other words, \(\mathtt{filter}\) should satisfy the following equivalences: \[\mathtt{filter}\,f\,โ[]โ โก_ฮฒ โ[]โ\] \[\mathtt{filter}\,f\,โa : lโ โก_ฮฒ ฮปc, n.c\,โaโ\,(\mathtt{filter}\,f\,โlโ\,c\,n)\,\,\,\,\,\,\,\,\,\,\,\,\text{(if }f\,โaโ โ_ฮฒ^* ๐\text{)}\] \[\mathtt{filter}\,f\,โa : lโ โก_ฮฒ \mathtt{filter}\,f\,โlโ\,\,\,\,\,\,\,\,\,\,\,\,\text{(if }f\,โaโ โ_ฮฒ^* ๐ฝ\text{)}\]