Thinking Functionally with Haskell (22 page)

BOOK: Thinking Functionally with Haskell
5.97Mb size Format: txt, pdf, ePub

mult x z
mult x z + 0

=
{since
x + 0 = x
}

mult x z

Case
y+1

mult (x+(y+1)) z
mult x z + mult (y+1) z
=
{as
(+)
is associative}
=
{
mult.2
}

mult ((x+y)+1) z
mult x z + (mult y z + z)
=
{
mult.2
}
=
{since
(+)
is associative}

mult (x+y) z + z
(mult x z + mult y z) + z
=
{induction}

(mult x z + mult y z) + z

Answer to Exercise B

The proof is by induction on
xs
:

Case
[]

reverse ([]++ys)
reverse ys ++ reverse []

=
{
++.1
}
=
{
reverse.1
}

reverse ys
reverse ys ++ []

=
{since
xs ++ [] = xs
}

reverse ys

Case
x:xs

reverse ((x:xs)++ys)

=
{
++.2
}

reverse (x:(xs++ys))

=
{
reverse.2
}

reverse (xs++ys) ++ [x]

=
{induction}

(reverse ys ++ reverse xs) ++ [x]

and

reverse ys ++ reverse (x:xs)

=
{
reverse.2
}

reverse ys ++ (reverse xs ++ [x])

=
{since
(++)
is associative}

(reverse ys ++ reverse xs) ++ [x]

Answer to Exercise C

We have to prove that

head (map f xs) = f (head xs)

for all lists
xs
, finite, partial or infinite. The case
undefined
and the inductive case
x:xs
are okay, but the case
[]
gives
head (map f []) = head [] = undefined

f (head [])
= f undefined

Hence the law holds only if
f
is a strict function. Eager Beaver is not bothered by this since he can only construct strict functions.

Answer to Exercise D

We have

cp = foldr op [[]]

where op xs xss = [x:ys | x <- xs, ys <- xss]

1.
length . cp = foldr h b
provided
length
is strict (it is) and
length [[]] = b

length (op xs xss) = h xs (length xss)

The first equation gives
b = 1
and as

length (op xs xss) = length xs * length xss

the second equation gives
h = (*) . length
.

2.
map length = foldr f []
, where
f xs ns = length xs:ns
. A shorter definition is
f = (:) . length
.

3.
product . map length = foldr h b
provided
product
is strict (it is) and
product [] = b

product (length xs:ns) = h xs (product ns)

The first equation gives
b = 1
, and as

product (length xs:ns) = length xs * product ns

the second equation gives
h = (*) . length
.

4. The two definitions of
h
and
b
are identical.

Answer to Exercise E

The definition of
foldN
is straightforward:

foldN :: (a -> a) -> a -> Nat -> a

foldN f e Zero = e

foldN f e (Succ n) = f (foldN f e n)

In particular,

m+n = foldN Succ m n

m*n = foldN (+m) Zero n

m^n = foldN (*m) (Succ Zero) n

For nonempty lists, the definition of
foldNE
is:

foldNE :: (a -> b -> b) -> (a -> b) -> NEList a -> b
foldNE f g (One x) = g x

foldNE f g (Cons x xs) = f x (foldNE f g xs)

To be a proper fold over nonempty lists, the correct definition of
foldr1
should have been
foldr1 :: (a -> b -> b) -> (a -> b) -> [a] -> b
foldr1 f g [x] = g x

foldr1 f g (x:xs) = f x (foldr1 f g xs)

The Haskell definition of
foldr1
restricts
g
to be the identity function.

Answer to Exercise F

Write
g = flip f
for brevity. We prove that

foldl f e xs = foldr g e (reverse xs)

for all finite lists
xs
by induction:

Case
[]

foldl f e []
foldl g e (reverse [])
=
{
foldl.1
}
=
{
reverse.1
}

e
foldl g e []

=
{
foldl.1
}

e

Case
x:xs

foldl f e (x:xs)

=
{
foldl.2
}

foldl f (f e x) xs

=
{induction}

foldr g (f e x) (reverse xs)

and

foldr g e (reverse (x:xs))

=
{
reverse.2
}

foldr g e (reverse xs ++ [x])

=
{claim: see below}

foldr g (foldr g e [x]) (reverse xs)

=
{since
foldr (flip f) e [x] = f e x
}

foldr g (f e x) (reverse xs)

The claim is that

foldr f e (xs ++ ys) = foldr f (foldr f e ys) xs

We leave the proof to the reader. By the way, we have the companion result that
foldl f e (xs ++ ys) = foldl f (foldl f e xs) ys

Again, the proof is left to you.

We prove

foldl (@) e xs = foldr (<>) e xs

for all finite lists
xs
by induction. The base case is trivial. For the inductive case:
Case
x:xs

foldl (@) e (x:xs)
foldr (<>) e (x:xs)
=
{
foldl.2
}
=
{
foldr.2
}

foldl (@) (e @ x) xs
x <> foldr (<>) e xs
=
{given that
e @ x = x <> e
}
=
{induction}

foldl (@) (x <> e) xs
x <> foldl (@) e xs
The two sides have simplified to different results. We need another induction hypothesis:
foldl (@) (x <> y) xs = x <> foldl (@) y xs

The base case is trivial. For the inductive case

Case
z:zs

foldl (@) (x <> y) (z:zs)

=
{
foldl.2
}

foldl (@) ((x <> y) @ z) zs

=
{since
(x <> y) @ z = x <> (y @ z)
}

foldl (@) (x <> (y @ z)) zs

=
{induction}

x <> foldl (@) (y @ z) zs

and

x <> foldl (@) y (z:zs)

=
{
foldl.2
}

x <> foldl (@) (y @ z) zs

Answer to Exercise G

The proofs are by induction. The base cases are easy and the inductive cases are
foldl f e (concat (xs:xss))

=
{definition of
concat
}

foldl f e (xs ++ concat xss)

=
{given property of
foldl
}

foldl f (foldl f e xs) (concat xss)

=
{induction}

foldl (foldl f) (foldl f e xs) xss

=
{definition of
foldl
}

foldl (foldl f) e (xs:xss)

and

foldr f e (concat (xs:xss))

=
{definition of
concat
}

foldr f e (xs ++ concat xss)

=
{given property of
foldr
}

foldr f (foldr f e (concat xss)) xs

=
{using
flip
}

flip (foldr f) xs (foldr f e (concat xss))

=
{induction}

flip (foldr f) xs (foldr (flip (foldr f)) e xss)

=
{definition of
foldr
}

foldr (flip (foldr f)) e (xs:xss)

Answer to Exercise H

Mathematically speaking,

sum (scanl (/) 1 [1..]) = e

since
Computationally speaking, replacing
[1..]
by a finite list
[1..n]
gives an approximation to
e
. For example,
ghci> sum (scanl (/) 1 [1..20])

2.7182818284590455

ghci> exp 1

2.718281828459045

The standard prelude function
exp
takes a number
x
and returns
e
x
. By the way, the prelude function
log
takes a number
x
and returns log
e
x
. If you want logarithms in another base, use
logBase
whose type is
logBase :: Floating a => a -> a -> a

Answer to Exercise I

We synthesise a more efficient definition by cases. The base case yields

scanr f e [] = [e]

and the inductive case
x:xs
is:
scanr f e (x:xs)

=
{specification}

map (foldr f e) (tails (x:xs))

=
{
tails.2
}

map (foldr f e) ((x:xs):tails xs)

=
{definition of
map
}

foldr f e (x:xs):map (foldr f e) (tails xs)

=
{
foldr.2
and specification}

f x (foldr f e xs):scan f e xs

=
{claim:
foldr f e xs = head (scanr f e xs)
}

f x (head ys):ys where ys = scanr f e xs

Answer to Exercise J

Firstly,

subseqs = foldr op [[]]

where op x xss = xss ++ map (x:) xss

Appeal to the fusion law yields

map sum . subseqs = foldr op [0]

where op x xs = xs ++ map (x+) xs

A second appeal to fusion yields

maximum . map sum . subseqs = foldr op 0

where op x y = y `max` (x+y)

That will do nicely. Of course,
sum . filter (>0)
also does the job.

Answer to Exercise K

1. We have

takePrefix nondec [1,3,7,6,8,9] = [1,3,7]

takePrefix (all even) [2,4,7,8] = [2,4]

The identity is

takePrefix (all p) = takeWhile p

The specification is

takePrefix p = last . filter p . inits

2. We have

none . f = none

map f . none = none

map f . one = one . f

3. We have

fst . fork (f,g) = f

snd . fork (f,g) = g

fork (f,g) . h = fork (f.h,g.h)

4. We have

test p (f,g) . h = test (p.h) (f . h, g . h)

h . test p (f,g) = test p (h . f, h . g)

The reasoning is:

map fst . filter snd . map (fork (id,p))

=
{definition of
filter
}

map fst . concat . map (test snd (one,none)) .

map (fork (id,p))

=
{since
map f . concat = concat . map (map f)
}

concat . map (map fst . test snd (one,none) .

fork (id,p))

=
{second law of
test
; laws of
one
and
none
}

concat . map (test snd (one . fst,none) .

fork (id,p))

=
{first law of
test
; laws of
fork
}

concat . map (test p (one . id, none . fork (id,p)))

=
{laws of
id
and
none
}

Other books

Winter Be My Shield by Spurrier, Jo
Patriotas by James Wesley Rawles
Wolf Hall by Hilary Mantel
Speak by Louisa Hall
El Libro Grande by Alcohólicos Anónimos
The Subatomic Kid by George Earl Parker
All Shall Be Well by Deborah Crombie
Waiting For Columbus by Thomas Trofimuk
Dr. Feelgood by Richard A. Lertzman, William J. Birnes