Haskell: List Comprehensions and higher-order functions - haskell

I've tried to transform the following list comprehension:
f xs = [ x+8 | (x,_) <- xs ]
using higher-order functions.
My first solution was:
f' xs = map (\(x,_) -> x+8) xs
After I tried various other approaches, I found out that the following also works:
f' xs = map((+8).fst) xs
Both versions of f' give the same (correct) output, but I don't understand why (+8).fst is equal to \(x,_) -> x+8 when using map on a list of tuples.

The definition of fst is
fst :: (a, b) -> a
fst (a, _) = a
and the definition of (.) is
(.) :: (b -> c) -> (a -> b) -> a -> c
(f . g) = \x -> f (g x)
If we use these definitions to expand your function, we get
f' xs = map ((+8) . fst) xs
f' xs = map (\x -> (+8) (fst x)) xs -- definition of (.)
f' xs = map (\x -> (+8) ((\(a, _) -> a) x)) -- definition of fst
f' xs = map (\(a, _) -> (+8) a) -- we can move the pattern matching
f' xs = map (\(a, _) -> a + 8) -- expand section

Both versions of f' give the same (correct) output, but I don't understand why (+8).fst is equal to (x,_) -> x+8 when using map on a list of tuples.
The type of fst is:
fst :: (a, b) -> a
and what it does is it takes the first element of a pair (a tuple of two elements).
The type of (+8) is:
(+8) :: Num a => a -> a
and what it does is it takes as input a Num, applies + 8 to it and returns the result.
Now, the type of (+8) . fst is:
((+8).fst) :: Num c => (c, b) -> c
which is the composition of fst and (+8). Specifically it's the function that takes as input a pair, extracts the first element and adds 8 to it.
This can be easily seen by seen an example:
((+8).fst) (3, 'a')
-- 11
The same thing happens with \ (x, _) -> x + 8. You take a pair as input (in the lambda), pattern match the first argument to x, increment it by 8 and return it:
(\ (x, _) -> x + 8) (3, 'a')
-- 11

Related

Rewrite using higher order functions

This code displays a list of the second elements of every tuple in xs based on the first element of the tuple (x).
For my assignment, I should define this in terms of higher order functions map and/or filter.
I came up with
j xs x = map snd . filter (\(a,_) -> a == x). xs
You can solve this by using parthesis and remove the last dot (.) before the xs:
j :: Eq a => [(a, b)] -> a -> [b]
j xs x = (map snd . filter ((a,_) -> a == x)) xs
here we thus construct a function between the parenthesis, and we use xs as argument. If you use f . x, then because of (.) :: (b -> c) -> (a -> b) -> a -> c, it expects x to be a function and it constructs a new function, but in your case xs is an argument, not another function to a use in the "chain".
The (a, _) -> a == x, can be replaced by (x ==) . fst:
j :: Eq a => [(a, b)] -> a -> [b]
j xs x = (map snd . filter ((x ==) . fst)) xs

Combining fragments of Haskell Code to get the bigger picture

This is the code that I came upon somewhere but want to know how this works:
findIndices :: (a -> Bool) -> [a] -> [Int]
findIndices _ [] = []
findIndices pred xs = map fst (filter (pred . snd) (zip [0..] xs))
Output: findIndices (== 0) [1,2,0,3,0] == [2,4], where pred is (==0) & xs is [1,2,0,3,0]
I'll show some of my understanding:
(zip [0..] xs)
What the above line does is put indices to everything in the list. For the input given above, it would look like this: [(0,1),(1,2),(2,0),(3,3),(4,0)].
(pred . snd)
I found that this means something like pred (snd (x)). My question is, is x the list made from the zip line? I'm leaning towards yes but my guess is flimsy.
Next, is my understanding of fst and snd. I know that
fst(1,2) = 1
and
snd(1,2) = 2
How do these two commands make sense in the code?
My understanding of filter is that it returns a list of items that match a condition. For instance,
listBiggerThen5 = filter (>5) [1,2,3,4,5,6,7,8,9,10]
would give [6,7,8,9,10]
My understanding of map is that it applies a function to every item on the list. For instance,
times4 :: Int -> Int
times4 x = x * 4
listTimes4 = map times4 [1,2,3,4,5]
would give [4,8,12,16,20]
How does this work overall? I think I have been comprehensive in what I know so far but can't quite put the pieces together. Can anybody help me out?
I found that this means something like pred (snd (x)). My question is, is x the list made from the zip line? I'm leaning towards yes but my guess is flimsy.
Well pred . snd, means \x -> pred (snd x). So this basically constructs a function that maps an element x on pred (snd x).
This thus means that the expression looks like:
filter (\x -> pred (snd x)) (zip [0..] xs)
Here x is thus a 2-tuple generated by zip. So in order to know if (0, 1), (1,2), (2, 0), etc. are retained in the result, snd x will take the second element of these 2-tuples (so 1, 2, 0, etc.), and check if the pred on tha element is satisfied or not. If it is satisfied, it will retain the element, otherwise that element (the 2-tuple) is filtered out.
So if (== 0) is the predicate, then filter (pred . snd) (zip [0..] xs) will contain the 2-tuples [(2, 0), (4, 0)].
But now the result is a list of 2-tuples. If we want the indices, we somehow need to get rid of the 2-tuple, and the second element of these 2-tuples. We use fst :: (a, b) -> a for that: this maps a 2-tuple on its first element. So for a list [(2, 0), (4, 0)], map fst [(2, 0), (4, 0)] will return [2, 4].
In Haskell we like to say, follow the types. Indeed the pieces connect as if by wires going from type to corresponding type:
( first, function composition is:
(f >>> g) x = (g . f) x = g (f x)
(f >>> g) = (g . f) = \x -> g (f x)
and function composition type inference rule is:
f :: a -> b -- x :: a
g :: b -> c -- f x :: b
------------------------- -- g (f x) :: c
f >>> g :: a -> c
g . f :: a -> c
Now, )
findIndices :: (b -> Bool) -> [b] -> [Int]
findIndices pred = \xs -> map fst ( filter (pred . snd) ( zip [0..] xs ))
= map fst . filter (pred . snd) . zip [0..]
= zip [0..] >>> filter (snd >>> pred) >>> map fst
---------------------------------------------------------------------------
zip :: [a] -> [b] -> [(a, b)]
zip [0..] :: [b] -> [(Int,b)]
---------------------------------------------------------------------------
snd :: (a,b) -> b
pred :: b -> Bool
------------------------------------
(snd >>> pred) :: (a,b) -> Bool
---------------------------------------------------------------------------
filter :: (t -> Bool) -> [t] -> [t]
filter (snd >>> pred) :: [(a,b)] -> [(a,b)]
filter (snd >>> pred) :: [(Int,b)] -> [(Int,b)]
---------------------------------------------------------------------------
fst :: (a, b) -> a
map :: (t -> s) -> [t] -> [s]
map fst :: [(a,b)] -> [a]
map fst :: [(Int,b)] -> [Int]
so, overall,
zip [0..] :: [b] -> [(Int,b)]
filter (snd >>> pred) :: [(Int,b)] -> [(Int,b)]
map fst :: [(Int,b)] -> [Int]
---------------------------------------------------------------------------
findIndices pred :: [b] -> [Int]
You've asked, how do these pieces fit together?
This is how.
With list comprehensions, your function is written as
findIndices pred xs = [ i | (i,x) <- zip [0..] xs, pred x ]
which in pseudocode reads:
"result list contains i for each (i,x) in zip [0..] xs such that pred x holds".
It does this by turning the n-long
xs = [a,b,...,z] = [a] ++ [b] ++ ... ++ [z]
into
[0 | pred a] ++ [1 | pred b] ++ ... ++ [n-1 | pred z]
where [a | True] is [a] and [a | False] is [].

map function using foldl or foldr in Haskell

I am writing a function my_map which takes a unary function and a list and returns the list resulting from mapping the function over all elements of the input list.
Main> my_map (^3) [1..5]
[1,8,27,64,125]
I tried it like this:
my_map :: (a -> b) -> [a] -> [b]
my_map f [] = []
my_map f (x:xs) = foldr (\x xs -> (f x):xs) [] xs
But after running above, I get only [8,27,64,125]. the first number 1 is not displaying in output.
Can anybody help me?
You are using the (x:xs) pattern in your arguments, but when you apply the fold, you only apply it to the xs part, which means your first element i.e. the one that x represents never gets processed. You need to change it to this:
my_map :: (a -> b) -> [a] -> [b]
my_map f xs = foldr (\y ys -> (f y):ys) [] xs
Since you are using foldr, you do not need to explicitly handle the empty list case. Moreoever, you do not need to specify the list in (x:xs) format.
Finally, my own preference is to avoid using the same name for function inputs and any helper functions or expressions in the function definition.That is why, I have used xs for the input list and y and ys for the parameters passed to the lambda.
"shree.pat18" is perfectly right, and also the comments are valuable. I learned a lot from that. Just make it better visible, and to explain the alternatives...
Answer
-- The problem is here ....................... vv
my_map f (x:xs) = foldr (\x xs -> (f x):xs) [] xs
-- --
The remaining part xs is aplied to foldr.
To fix just this, apply the whole list. This can be done by placing xx# before (x:xs). By that, the whole list is bound to xx.
-- vvv ........... see here ............... vv
my_map f xx#(x:xs) = foldr (\x xs -> (f x):xs) [] xx
-- --- --
Recommended impovement
Note: foldr can already deal with [] as input. Hence, my_map f [] = [] is not needed. But foldr would not be called when you apply [] to my_map. To get rid of my_map f [] = [], you need to remove the pattern matching, because (x:xs) matches only to lists with at least one element.
main :: IO ()
main = print $ my_map (^(3 :: Int)) ([1..5] :: [Integer])
my_map :: (a -> b) -> [a] -> [b]
my_map f xx = foldr (\x xs -> (f x):xs) [] xx
The answer is complete here. The rest below is for pleasure.
Further reductions
Simple expression instead of lambda expression
If you want to reduce the lambda expression (\x xs -> (f x):xs), as suggested by "Aadit M Shah"...
(:) is equal to (\x xs -> x:xs), because : is an operator and its function is (:)
. can be used to combine the function f with (:), hence (\x xs -> (f x):xs) is equal to ((:) . f)
main :: IO ()
main = print $ my_map (^(3 :: Int)) ([] :: [Integer])
my_map :: (a -> b) -> [a] -> [b]
my_map f xx = foldr ((:) . f) [] xx
Currying
A function of the form
-- v v
f a b c = .... c
can be reduced to
-- v v
f a b = ....
and a function of the form
-- v v v v
f a b c = .... b c
can be reduced to
-- v v v v
f a = ....
and so on, by currying.
Hence, my_map f xx = foldr ((:) . f) [] xx equals my_map f = foldr ((:) . f) [].
Combination and flip
flip flips the first two parameters.
Example, the following functions are equal:
f' a b c = (\c' b' a' -> ((a' - b') / c')) b a c
f'' a b c = flip (\c' b' a' -> ((a' - b') / c')) a b c
f''' = flip (\c' b' a' -> ((a' - b') / c'))
Hence, the following code works as well.
main :: IO ()
main = print $ my_map (^(3 :: Int)) ([1..5] :: [Integer])
my_map :: (a -> b) -> [a] -> [b]
my_map f = flip foldr [] ((:) . f)
But we can not get rid of f as above, because of the form in the expression flip foldr [] ((:) . f).
If we remove f ...
`((:) . f)` has type `a -> [a] -> [a]
-- v
`((:) . )` has type `(a -> a) -> a -> [a] -> [a]`
and
`flip foldr []` has type `Foldable t => (a1 -> [a2] -> [a2]) -> t a1 -> [a2]`
hence
f :: a -> a
is passed to
((:) . )
becomming
a -> [a] -> [a]
is passed to
flip foldr []
becomming
t a1 -> [a2]
Hence,
main :: IO ()
main = print $ my_map (^(3 :: Int)) ([1..5] :: [Integer])
my_map :: (a -> b) -> [a] -> [b]
my_map = flip foldr [] . ((:) . )
works nicely.

Why can you reverse list with foldl, but not with foldr in Haskell

Why can you reverse a list with the foldl?
reverse' :: [a] -> [a]
reverse' xs = foldl (\acc x-> x : acc) [] xs
But this one gives me a compile error.
reverse' :: [a] -> [a]
reverse' xs = foldr (\acc x-> x : acc) [] xs
Error
Couldn't match expected type `a' with actual type `[a]'
`a' is a rigid type variable bound by
the type signature for reverse' :: [a] -> [a] at foldl.hs:33:13
Relevant bindings include
x :: [a] (bound at foldl.hs:34:27)
acc :: [a] (bound at foldl.hs:34:23)
xs :: [a] (bound at foldl.hs:34:10)
reverse' :: [a] -> [a] (bound at foldl.hs:34:1)
In the first argument of `(:)', namely `x'
In the expression: x : acc
Every foldl is a foldr.
Let's remember the definitions.
foldr :: (a -> s -> s) -> s -> [a] -> s
foldr f s [] = s
foldr f s (a : as) = f a (foldr f s as)
That's the standard issue one-step iterator for lists. I used to get my students to bang on the tables and chant "What do you do with the empty list? What do you do with a : as"? And that's how you figure out what s and f are, respectively.
If you think about what's happening, you see that foldr effectively computes a big composition of f a functions, then applies that composition to s.
foldr f s [1, 2, 3]
= f 1 . f 2 . f 3 . id $ s
Now, let's check out foldl
foldl :: (t -> a -> t) -> t -> [a] -> t
foldl g t [] = t
foldl g t (a : as) = foldl g (g t a) as
That's also a one-step iteration over a list, but with an accumulator which changes as we go. Let's move it last, so that everything to the left of the list argument stays the same.
flip . foldl :: (t -> a -> t) -> [a] -> t -> t
flip (foldl g) [] t = t
flip (foldl g) (a : as) t = flip (foldl g) as (g t a)
Now we can see the one-step iteration if we move the = one place leftward.
flip . foldl :: (t -> a -> t) -> [a] -> t -> t
flip (foldl g) [] = \ t -> t
flip (foldl g) (a : as) = \ t -> flip (foldl g) as (g t a)
In each case, we compute what we would do if we knew the accumulator, abstracted with \ t ->. For [], we would return t. For a : as, we would process the tail with g t a as the accumulator.
But now we can transform flip (foldl g) into a foldr. Abstract out the recursive call.
flip . foldl :: (t -> a -> t) -> [a] -> t -> t
flip (foldl g) [] = \ t -> t
flip (foldl g) (a : as) = \ t -> s (g t a)
where s = flip (foldl g) as
And now we're good to turn it into a foldr where type s is instantiated with t -> t.
flip . foldl :: (t -> a -> t) -> [a] -> t -> t
flip (foldl g) = foldr (\ a s -> \ t -> s (g t a)) (\ t -> t)
So s says "what as would do with the accumulator" and we give back \ t -> s (g t a) which is "what a : as does with the accumulator". Flip back.
foldl :: (t -> a -> t) -> t -> [a] -> t
foldl g = flip (foldr (\ a s -> \ t -> s (g t a)) (\ t -> t))
Eta-expand.
foldl :: (t -> a -> t) -> t -> [a] -> t
foldl g t as = flip (foldr (\ a s -> \ t -> s (g t a)) (\ t -> t)) t as
Reduce the flip.
foldl :: (t -> a -> t) -> t -> [a] -> t
foldl g t as = foldr (\ a s -> \ t -> s (g t a)) (\ t -> t) as t
So we compute "what we'd do if we knew the accumulator", and then we feed it the initial accumulator.
It's moderately instructive to golf that down a little. We can get rid of \ t ->.
foldl :: (t -> a -> t) -> t -> [a] -> t
foldl g t as = foldr (\ a s -> s . (`g` a)) id as t
Now let me reverse that composition using >>> from Control.Arrow.
foldl :: (t -> a -> t) -> t -> [a] -> t
foldl g t as = foldr (\ a s -> (`g` a) >>> s) id as t
That is, foldl computes a big reverse composition. So, for example, given [1,2,3], we get
foldr (\ a s -> (`g` a) >>> s) id [1,2,3] t
= ((`g` 1) >>> (`g` 2) >>> (`g` 3) >>> id) t
where the "pipeline" feeds its argument in from the left, so we get
((`g` 1) >>> (`g` 2) >>> (`g` 3) >>> id) t
= ((`g` 2) >>> (`g` 3) >>> id) (g t 1)
= ((`g` 3) >>> id) (g (g t 1) 2)
= id (g (g (g t 1) 2) 3)
= g (g (g t 1) 2) 3
and if you take g = flip (:) and t = [] you get
flip (:) (flip (:) (flip (:) [] 1) 2) 3
= flip (:) (flip (:) (1 : []) 2) 3
= flip (:) (2 : 1 : []) 3
= 3 : 2 : 1 : []
= [3, 2, 1]
That is,
reverse as = foldr (\ a s -> (a :) >>> s) id as []
by instantiating the general transformation of foldl to foldr.
For mathochists only. Do cabal install newtype and import Data.Monoid, Data.Foldable and Control.Newtype. Add the tragically missing instance:
instance Newtype (Dual o) o where
pack = Dual
unpack = getDual
Observe that, on the one hand, we can implement foldMap by foldr
foldMap :: Monoid x => (a -> x) -> [a] -> x
foldMap f = foldr (mappend . f) mempty
but also vice versa
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f = flip (ala' Endo foldMap f)
so that foldr accumulates in the monoid of composing endofunctions, but now to get foldl, we tell foldMap to work in the Dual monoid.
foldl :: (b -> a -> b) -> b -> [a] -> b
foldl g = flip (ala' Endo (ala' Dual foldMap) (flip g))
What is mappend for Dual (Endo b)? Modulo wrapping, it's exactly the reverse composition, >>>.
For a start, the type signatures don't line up:
foldl :: (o -> i -> o) -> o -> [i] -> o
foldr :: (i -> o -> o) -> o -> [i] -> o
So if you swap your argument names:
reverse' xs = foldr (\ x acc -> x : acc) [] xs
Now it compiles. It won't work, but it compiles now.
The thing is, foldl, works from left to right (i.e., backwards), whereas foldr works right to left (i.e., forwards). And that's kind of why foldl lets you reverse a list; it hands you stuff in reverse order.
Having said all that, you can do
reverse' xs = foldr (\ x acc -> acc ++ [x]) [] xs
It'll be really slow, however. (Quadratic complexity rather than linear complexity.)
You can use foldr to reverse a list efficiently (well, most of the time in GHC 7.9—it relies on some compiler optimizations), but it's a little weird:
reverse xs = foldr (\x k -> \acc -> k (x:acc)) id xs []
I wrote an explanation of how this works on the Haskell Wiki.
foldr basically deconstructs a list, in the canonical way: foldr f initial is the same as a function with patterns:(this is basically the definition of foldr)
ff [] = initial
ff (x:xs) = f x $ ff xs
i.e. it un-conses the elements one by one and feeds them to f. Well, if all f does is cons them back again, then you get the list you originally had! (Another way to say that: foldr (:) [] ≡ id.
foldl "deconstructs" the list in inverse order, so if you cons back the elements you get the reverse list. To achieve the same result with foldr, you need to append to the "wrong" end – either as MathematicalOrchid showed, inefficiently with ++, or by using a difference list:
reverse'' :: [a] -> [a]
reverse'' l = dl2list $ foldr (\x accDL -> accDL ++. (x:)) empty l
type DList a = [a]->[a]
(++.) :: DList a -> DList a -> DList a
(++.) = (.)
emptyDL :: DList a
emptyDL = id
dl2list :: DLList a -> [a]
dl2list = ($[])
Which can be compactly written as
reverse''' l = foldr (flip(.) . (:)) id l []
This is what foldl op acc does with a list with, say, 6 elements:
(((((acc `op` x1) `op` x2) `op` x3) `op` x4) `op` x5 ) `op` x6
while foldr op acc does this:
x1 `op` (x2 `op` (x3 `op` (x4 `op` (x5 `op` (x6 `op` acc)))))
When you look at this, it becomes clear that if you want foldl to reverse the list, op should be a "stick the right operand to the beginning of the left operand" operator. Which is just (:) with arguments reversed, i.e.
reverse' = foldl (flip (:)) []
(this is the same as your version but using built-in functions).
When you want foldr to reverse the list, you need a "stick the left operand to the end of the right operand" operator. I don't know of a built-in function that does that; if you want you can write it as flip (++) . return.
reverse'' = foldr (flip (++) . return) []
or if you prefer to write it yourself
reverse'' = foldr (\x acc -> acc ++ [x]) []
This would be slow though.
A slight but significant generalization of several of these answers is that you can implement foldl with foldr, which I think is a clearer way of explaining what's going on in them:
myMap :: (a -> b) -> [a] -> [b]
myMap f = foldr step []
where step a bs = f a : bs
-- To fold from the left, we:
--
-- 1. Map each list element to an *endomorphism* (a function from one
-- type to itself; in this case, the type is `b`);
--
-- 2. Take the "flipped" (left-to-right) composition of these
-- functions;
--
-- 3. Apply the resulting function to the `z` argument.
--
myfoldl :: (b -> a -> b) -> b -> [a] -> b
myfoldl f z as = foldr (flip (.)) id (toEndos f as) z
where
toEndos :: (b -> a -> b) -> [a] -> [b -> b]
toEndos f = myMap (flip f)
myReverse :: [a] -> [a]
myReverse = myfoldl (flip (:)) []
For more explanation of the ideas here, I'd recommend reading Tom Ellis' "What is foldr made of?" and Brent Yorgey's "foldr is made of monoids".

Church lists in Haskell

I had to implement the haskell map function to work with church lists which are defined as following:
type Churchlist t u = (t->u->u)->u->u
In lambda calculus, lists are encoded as following:
[] := λc. λn. n
[1,2,3] := λc. λn. c 1 (c 2 (c 3 n))
The sample solution of this exercise is:
mapChurch :: (t->s) -> (Churchlist t u) -> (Churchlist s u)
mapChurch f l = \c n -> l (c.f) n
I have NO idea how this solution works and I don't know how to create such a function. I have already experience with lambda calculus and church numerals, but this exercise has been a big headache for me and I have to be able to understand and solve such problems for my exam next week. Could someone please give me a good source where I could learn to solve such problems or give me a little guidance on how it works?
All lambda calculus data structures are, well, functions, because that's all there is in the lambda calculus. That means that the representation for a boolean, tuple, list, number, or anything, has to be some function that represents the active behavior of that thing.
For lists, it is a "fold". Immutable singly-linked lists are usually defined List a = Cons a (List a) | Nil, meaning the only ways you can construct a list is either Nil or Cons anElement anotherList. If you write it out in lisp-style, where c is Cons and n is Nil, then the list [1,2,3] looks like this:
(c 1 (c 2 (c 3 n)))
When you perform a fold over a list, you simply provide your own "Cons" and "Nil" to replace the list ones. In Haskell, the library function for this is foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
Look familiar? Take out the [a] and you have the exact same type as Churchlist a b. Like I said, church encoding represents lists as their folding function.
So the example defines map. Notice how l is used as a function: it is the function that folds over some list, after all. \c n -> l (c.f) n basically says "replace every c with c . f and every n with n".
(c 1 (c 2 (c 3 n)))
-- replace `c` with `(c . f)`, and `n` with `n`
((c . f) 1 ((c . f) 2) ((c . f) 3 n)))
-- simplify `(foo . bar) baz` to `foo (bar baz)`
(c (f 1) (c (f 2) (c (f 3) n))
It should be apparent now that this is indeed a mapping function, because it looks just like the original, except 1 turned into (f 1), 2 to (f 2), and 3 to (f 3).
So let's start by encoding the two list constructors, using your example as reference:
[] := λc. λn. n
[1,2,3] := λc. λn. c 1 (c 2 (c 3 n))
[] is the end of list constructor, and we can lift that straight from the example. [] already has meaning in haskell, so let's call ours nil:
nil = \c n -> n
The other constructor we need takes an element and an existing list, and creates a new list. Canonically, this is called cons, with the definition:
cons x xs = \c n -> c x (xs c n)
We can check that this is consistent with the example above, since
cons 1 (cons 2 (cons 3 nil))) =
cons 1 (cons 2 (cons 3 (\c n -> n)) =
cons 1 (cons 2 (\c n -> c 3 ((\c' n' -> n') c n))) =
cons 1 (cons 2 (\c n -> c 3 n)) =
cons 1 (\c n -> c 2 ((\c' n' -> c' 3 n') c n) ) =
cons 1 (\c n -> c 2 (c 3 n)) =
\c n -> c 1 ((\c' n' -> c' 2 (c' 3 n')) c n) =
\c n -> c 1 (c 2 (c 3 n)) =
Now, consider the purpose of the map function - it is to apply the given function to each element of the list. So let's see how that works for each of the constructors.
nil has no elements, so mapChurch f nil should just be nil:
mapChurch f nil
= \c n -> nil (c.f) n
= \c n -> (\c' n' -> n') (c.f) n
= \c n -> n
= nil
cons has an element and a rest of list, so, in order for mapChurch f to work propery, it must apply f to the element and mapChurch f to rest of the list. That is, mapChurch f (cons x xs) should be the same as cons (f x) (mapChurch f xs).
mapChurch f (cons x xs)
= \c n -> (cons x xs) (c.f) n
= \c n -> (\c' n' -> c' x (xs c' n')) (c.f) n
= \c n -> (c.f) x (xs (c.f) n)
-- (c.f) x = c (f x) by definition of (.)
= \c n -> c (f x) (xs (c.f) n)
= \c n -> c (f x) ((\c' n' -> xs (c'.f) n') c n)
= \c n -> c (f x) ((mapChurch f xs) c n)
= cons (f x) (mapChurch f xs)
So since all lists are made from those two constructors, and mapChurch works on both of them as expected, mapChurch must work as expected on all lists.
Well, we can comment the Churchlist type this way to clarify it:
-- Tell me...
type Churchlist t u = (t -> u -> u) -- ...how to handle a pair
-> u -- ...and how to handle an empty list
-> u -- ...and then I'll transform a list into
-- the type you want
Note that this is intimately related to the foldr function:
foldr :: (t -> u -> u) -> u -> [t] -> u
foldr k z [] = z
foldr k z (x:xs) = k x (foldr k z xs)
foldr is a very general function that can implement all sorts of other list functions. A trivial example that will help you is implementing a list copy with foldr:
copyList :: [t] -> [t]
copyList xs = foldr (:) [] xs
Using the commented type above, foldr (:) [] means this: "if you see an empty list return the empty list, and if you see a pair return head:tailResult."
Using Churchlist, you can easily write the counterpart this way:
-- Note that the definitions of nil and cons mirror the two foldr equations!
nil :: Churchlist t u
nil = \k z -> z
cons :: t -> Churchlist t u -> Churchlist t u
cons x xs = \k z -> k x (xs k z)
copyChurchlist :: ChurchList t u -> Churchlist t u
copyChurchlist xs = xs cons nil
Now, to implement map, you just need to replace cons with a suitable function, like this:
map :: (a -> b) -> [a] -> [b]
map f xs = foldr (\x xs' -> f x:xs') [] xs
Mapping is like copying a list, except that instead of just copying the elements verbatim you apply f to each of them.
Study all of this carefully, and you should be able to write mapChurchlist :: (t -> t') -> Churchlist t u -> Churchlist t' u on your own.
Extra exercise (easy): write these list functions in terms of foldr, and write counterparts for Churchlist:
filter :: (a -> Bool) -> [a] -> [a]
append :: [a] -> [a] -> [a]
-- Return first element of list that satisfies predicate, or Nothing
find :: (a -> Bool) -> [a] -> Maybe a
If you're feeling like tackling something harder, try writing tail for Churchlist. (Start by writing tail for [a] using foldr.)

Resources