Posted on June 17, 2016
by Taran Lynn
Note: The church encoded type aliases require Rank2Types or RankNTypes. Church encoding is a technique whereby data structures are represented by functions. To this end it can be shown that any Haskell ADT can be represented by a function. I will be ignoring GADTs, and focus only on product and sum types. To start, lets look at how product types can be encoded as a function. I will use a triple, or 3-element tuple, as my example. First we can see the normal ADT definition.
One possible way to encode this as a function is as a function that takes another function as an argument and passes its stored values to that function. To see how this works, we can look at the type alias and constructor for the church encoded version.
To create a triple we simply need to pass the data we want to store into this
function, such as It’s also interesting to see how church encoding relates to pattern matching. For example, the following
can be directly translated to the ADT version as
This relation to pattern matching is more interesting for types that containt
both sums and products, but first lets discuss pure sums. The simplest example
is a boolean value
We can now see that we can choose different values based on whether we have a true or false value. To see why this important let’s look at another pattern matching example. The ADT version
can be translated to the function encoded version as
This shows that the choice encoded into the function representation is directly related to the choice made in pattern matching. A more interesting case is when we have a of the two previous cases. The typical example would be the Either type. These cases can be encoded as a function that takes multiple functions as arguments, and selectively applies its contained values to those functions. The encoding of Either is thus
Like the other encodings, this one also has a relation to pattern matching. The following
can be directly translated to a pattern match as
These methods can be used to encode most ADTs, with one exception that I’ll get to. First, I’d like to demonstrate the power of these techniques with a more complicated example. The following
can be translated to
The area where church encoding ADTs becomes problematic is when encoding
recursively defined ADTs. The typical example of this is the List type, where
However, recursive type aliases are not allowed in Haskell. One way to overcome this issue by using a newtype declaration
We can then apply these lists using the
Note that this List encoding isn’t strictly a church encoding. This is because it is nonrepresentable in typed lambda calculus, due to the use of recursive types. A correct way to church encode List is as a fold.
Such an encoded list We can also encode the Tree type as a fold.
An encoded tree This shows that a general technique for encoding recursive ADTs is to replace
the recursive arguments with the church encoded function’s return type (which is
|