Download as pdf or txt
Download as pdf or txt
You are on page 1of 5

Prof. Dr.

Ralf Hinze TU Kaiserslautern


M.Sc. Sebastian Schloßer
Fachbereich Informatik
AG Programmiersprachen

Functional Programming: Exercise 10


Sheet published: Friday, July 8th
Exercise session: Thursday, July 14th, 12:00

Exercise 10.1. Show that this definition of the Reader Monad fulfils the Monad laws:

newtype Reader env a = Reader {runReader :: env → a }


instance Monad (Reader env ) where
return x = Reader (\ → x )
>= g = Reader (\x → runReader (g (f x )) x )
(Reader f ) >

For the proof, we leave out the Reader constructor and runReader accessor function:

return x = \ → x
f >>= g = \x → (g (f x )) x

f >>= return return a >>= f


= { def. >
>= } = { def. >>= }
\x → return (f x ) x \x → f (return a x ) x
= { def. return } = { def. return }
\x → f x \x → f a x
= { extensionality } = { extensionality }
f f a

(f >>= g) >
>= h
= { def. inner >
>= }
(\x → (g (f x )) x ) >
>= h
= { def. >
>= }
\x → (h (g (f x )) x ) x
= { extensionality, read the remaining proof bottom-up }
\x → (\x → (h (g (f x )) x ) x ) x
= { def. >
>= }
\x → (g (f x ) >
>= h) x
= { def. outer >
>= }
f >>= \a → (g a >
>= h)

1
Exercise 10.2 (Skeleton: Perfect.hs). Consider the following data type for trees con-
taining exactly 2n (n ∈ N) elements:

type Pair a = (a, a)


data Perfect a = Zero a
| Succ (Perfect (Pair a))

a) Write a function

height :: Perfect a → Integer

that calculates the height of the tree.

height (Zero ) = 1
height (Succ t) = 1 + height t

b) Write a function

toList :: Perfect a → [a ]

that transforms the tree to a list.

toList (Zero x ) = [x ]
toList (Succ t) = [z | (x , y) ← toList t, z ← [x , y ]]

c) Provide a Functor instance for Perfect and prove that it satisfies the first functor law.

instance Functor Perfect where


fmap f (Zero x ) = Zero (f x )
fmap f (Succ t) = Succ (fmap (\(x , y) → (f x , f y)) t)

Base case: Zero x


Need to show: fmap id (Zero x ) = Zero x

fmap id (Zero x )
= { def. fmap }
Zero (id x )
= { def. id }
Zero x

Induction step: Succ t


Induction Hypothesis: fmap id t = t
Need to show: fmap id (Succ t) = Succ t

2
fmap id (Succ t)
= { def. fmap }
Succ (fmap (\(x , y) → (id x , id y)) t)
= { def. id }
Succ (fmap (\(x , y) → (x , y)) t)
= { def. id (specialized to pair type) }
Succ (fmap id t)
= { induction hypothesis }
Succ t

d) Write a function

mirror :: Perfect a → Perfect a

that mirrors the tree such that toList ◦ mirror = reverse ◦ toList.

mirror (Zero x ) = Zero x


mirror (Succ t) = Succ (fmap (\(x , y) → (y, x )) (mirror t))

e) Write a function

fromList :: [a ] → Maybe (Perfect a)

that transforms the list into a perfect tree. This is possible only if the list contains
exactly 2n (n ∈ N) elements.

fromList [ ] = Nothing
fromList [x ] = Just (Zero x )
fromList xs = fmap Succ (pass xs >>= fromList) where
pass :: [a ] → Maybe [(a, a)]
pass [ ] = Just [ ]
pass [ ] = Nothing
pass (x : y : zs) = fmap ((x , y):) (pass zs)

3
Exercise 10.3 (Skeleton: Lists.hs). Lists can be represented as functions:

newtype ChurchList a = CL (∀b.(a → b → b) → b → b)

The type ChurchList a is isomorphic to the type [a ]. The ChurchList a representation


takes a binary operation (a → b → b) and an initial value (b). It applies the operation to
all elements from the list plus the initial value in a right-associative way. Think of it as
an instance of the foldr function where the list has already been provided.

a) Provide representations for both list constructors:

nil :: ChurchList a
cons :: a → ChurchList a → ChurchList a

nil = CL $ \ r → r
cons x (CL xs) = CL $ \f r → f x (xs f r )

b) We also need a way to consume lists of type ChurchList a. Implement a function

foldr :: (a → b → b) → b → ChurchList a → b

that behaves like foldr for normal Haskell lists of type [a ].

foldr f y (CL xs) = xs f y

c) Provide a Functor instance for ChurchList, i.e. implement a function

fmap :: (a → b) → ChurchList a → ChurchList b

We could just use foldr :

fmap f xs = foldr (\x ys → cons (f x ) ys) nil xs

We can simplify it to a direct implementation:

fmap f (CL xs) = CL $ \g → xs (g ◦ f )

4
d) Implement functions

fromList :: [a ] → ChurchList a
toList :: ChurchList a → [a ]

that convert normal Haskell lists to our ChurchList a representation and vice verca.

fromList = foldr cons nil


toList = foldr (:) [ ]

Instead of using cons and nil , we can also provide a direct implementation:

fromList xs = CL $ \f r → foldr f r xs

e) Implement functions

safeHead :: ChurchList a → Maybe a


safeTail :: ChurchList a → Maybe (ChurchList a)
append :: ChurchList a → ChurchList a → ChurchList a

that correspond to head , tail and ++ for normal lists of type [a ]. Note that safeHead
and safeTail have a Maybe return type to handle empty input lists.

safeHead (CL xs) = xs (\a → Just a) Nothing


safeTail (CL xs) = snd (xs (\x ∼(r , ) → (cons x r , Just r )) (nil , Nothing))
append (CL xs) (CL ys) = CL $ \f r → xs f (ys f r )

The tilde (∼) in safeTail makes the pattern match lazya . The lambda expression
is equivalent to \x pair → let (r , ) = pair in (cons x r , Just r ). Lazy pattern
matching is required here to ensure that safeTail always is productive; think of e.g.
safeTail (fromList [1 . .]) which otherwise hangs without producing output.
safeHead and append are constant time operations, safeTail needs linear time. For
normal Haskell lists, head and tail are constant time, whereas ++ needs time linear
in the length of the first parameter.
In the interpreter, type :set +s to enable statistics and then compare:

iiii length $ foldr (+


+) [] (take 10000 (repeat [1]))
iiii length $ foldl (+
+) [] (take 10000 (repeat [1]))
iiii length $ foldr append nil (take 10000 (repeat (cons 1 nil )))
iiii length $ foldl append nil (take 10000 (repeat (cons 1 nil )))

a
https://wiki.haskell.org/Lazy_pattern_match

You might also like