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

Prof. Dr.

Ralf Hinze TU Kaiserslautern


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

Functional Programming: Exercise 1


Sheet published: Monday, May 2nd
Exercise session: Thursday, May 5th

Install Haskell Please follow the installation instructions in our Olat course1 .

Task annotations Tasks annotated with “Pen and paper” should be solved without the
computer. Tasks that are annotated with a filename come with a skeleton file.

Exercise 1.1 (Pen and paper).


a) Recall the implementation of Insertion Sort from §0.5 (listed below, with some minor
modifications).

insertionSort :: [Integer ] → [Integer ]


insertionSort [ ] = []
insertionSort (x : xs) = insert x (insertionSort xs)
insert :: Integer → [Integer ] → [Integer ]
insert a [ ] = a : [ ]
insert a (b : xs)
| a 6 b = a : b : xs
| a > b = b : insert a xs

The function insert takes an element and an ordered list and inserts the element at the
appropriate position, e.g.

insert 7 (2 : (9 : [ ]))
=⇒ { definition of insert and 7 > 2 }
2 : (insert 7 (9 : [ ]))
=⇒ { definition of insert and 7 6 9 }
2 : (7 : (9 : [ ]))

Recall that Haskell has a very simple computational model: an expression is evaluated
by repeatedly replacing equals by equals. Evaluate (by hand, using the format above)
the expression insertionSort (7 : (9 : (2 : [ ]))).

1
https://olat.vcrp.de/auth/RepositoryEntry/3699835287/CourseNode/103642058062139

1
insertionSort (7 : (9 : (2 : [ ])))
=⇒ { definition of insertionSort }
insert 7 (insertionSort (9 : (2 : [ ])))
=⇒ { definition of insertionSort }
insert 7 (insert 9 (insertionSort (2 : [ ])))
=⇒ { definition of insertionSort }
insert 7 (insert 9 (insert 2 (insertionSort [ ])))
=⇒ { definition of insertionSort }
insert 7 (insert 9 (insert 2 [ ]))
=⇒ { definition of insert }
insert 7 (insert 9 (2 : [ ]))
=⇒ { definition of insert and 9 > 2 }
insert 7 (2 : (insert 9 [ ]))
=⇒ { definition of insert and 7 > 2 }
2 : (insert 7 (insert 9 [ ]))
=⇒ { definition of insert }
2 : (insert 7 (9 : [ ]))
=⇒ { definition of insert and 7 6 9 }
2 : (7 : (9 : [ ]))

2
b) The function twice applies its first argument twice to its second argument.

twice f x = f (f x )

(Like map and filter , it is an example of a higher-order function as it takes a function


as an argument.) Evaluate twice (+1) 0 and twice twice (∗2) 1 by hand.

twice (+1) 0
=⇒ { definition of twice }
(+1) ((+1) 0)
=⇒ { (+1) n = n + 1 }
((+1) 0) + 1
=⇒ { (+1) n = n + 1 }
(0 + 1) + 1
=⇒ { definition of (+) }
1+1
=⇒ { definition of (+) }
2

3
For the second expression, note that function application is left-associative. The
expression to evaluate therefore is ((twice twice) (∗2)) 1. To clarify what happens,
we split inserting the definition and applying arguments in separate steps.

((twice twice) (∗2)) 1


=⇒ { definition of (left) twice }
(((\f x → f (f x )) twice) (∗2)) 1
=⇒ { β rule }
((\x → twice (twice x )) (∗2)) 1
=⇒ { β rule }
(twice (twice (∗2))) 1
=⇒ { definition of (left) twice }
((\f x → f (f x )) (twice (∗2))) 1
=⇒ { β rule }
(\x → (twice (∗2)) ((twice (∗2)) x )) 1
=⇒ { β rule }
((twice (∗2)) ((twice (∗2)) 1))
=⇒ { definition of (left) twice }
(((\f x → f (f x )) (∗2)) ((twice (∗2)) 1))
=⇒ { β rule }
(\x → (∗2) ((∗2) x )) ((twice (∗2)) 1)
=⇒ { β rule }
(∗2) ((∗2) ((twice (∗2)) 1))
=⇒ { (∗2) n = n ∗ 2 }
((∗2) ((twice (∗2)) 1)) ∗ 2
=⇒ { (∗2) n = n ∗ 2 }
(((twice (∗2)) 1) ∗ 2) ∗ 2
=⇒ { definition of twice }
((((\f x → f (f x )) (∗2)) 1) ∗ 2) ∗ 2
=⇒ { β rule }
((((\x → (∗2) ((∗2) x ))) 1) ∗ 2) ∗ 2
=⇒ { β rule }
(((∗2) ((∗2) 1)) ∗ 2) ∗ 2
=⇒ { (∗2) n = n ∗ 2 }
((((∗2) 1) ∗ 2) ∗ 2) ∗ 2
=⇒ { (∗2) n = n ∗ 2 }
(((1 ∗ 2) ∗ 2) ∗ 2) ∗ 2
=⇒ { evaluate ∗ }
16

4
Use the computer to evaluate

iiii twice ("|"++) ""


iiii twice twice ("|"++) ""
iiii twice twice twice ("|"++) ""
iiii twice twice twice twice ("|"++) ""
iiii twice (twice twice) ("|"++) ""
iiii twice twice (twice twice) ("|"++) ""
iiii twice (twice (twice twice)) ("|"++) ""

Is there any rhyme or rhythm? Can you identify any pattern?

Church encoding for natural number n in lambda calculus: λf.λx.f n x. Using that
encoding, m ◦ n represents nm . The function twice represents the number 2. Since
function application is left-associative, we have:
• twice: 2
• twice ◦ twice: 22 = 4
2
• twice ◦ twice ◦ twice = (twice ◦ twice) ◦ twice: 2(2 ) = 24 = 16
• twice

◦twice ◦ twice ◦ twice = ((twice ◦ twice) ◦ twice) ◦ twice:
( 22 )
2 4
2 = 2(2 ) = 216 = 65536
2
• twice ◦ (twice ◦ twice): 22 = 42 = 16
 22
• twice ◦twice ◦(twice ◦twice) = (twice ◦twice)◦(twice ◦twice): 22 ( ) = 44 = 256
  2
2 2
• twice ◦ (twice ◦ (twice ◦ twice)): 22 = 42 = 162 = 256

5
Exercise 1.2. Define the string thisOldMan :: String that produces the following poem
(if you type putStr thisOldMan).
This old man, he played one,
He played knick-knack on my thumb;
With a knick-knack paddywhack,
Give the dog a bone,
This old man came rolling home.

This old man, he played two,


He played knick-knack on my shoe;
With a knick-knack paddywhack,
Give the dog a bone,
This old man came rolling home.

This old man, he played three,


He played knick-knack on my knee;
With a knick-knack paddywhack,
Give the dog a bone,
This old man came rolling home.

This old man, he played four,


He played knick-knack on my door;
With a knick-knack paddywhack,
Give the dog a bone,
This old man came rolling home.

This old man, he played five,


He played knick-knack on my hive;
With a knick-knack paddywhack,
Give the dog a bone,
This old man came rolling home.

This old man, he played six,


He played knick-knack on my sticks;
With a knick-knack paddywhack,
Give the dog a bone,
This old man came rolling home.

This old man, he played seven,


He played knick-knack up in heaven;
With a knick-knack paddywhack,
Give the dog a bone,
This old man came rolling home.

This old man, he played eight,


He played knick-knack on my gate;
With a knick-knack paddywhack,
Give the dog a bone,
This old man came rolling home.

This old man, he played nine,


He played knick-knack on my spine;
With a knick-knack paddywhack,
Give the dog a bone,
This old man came rolling home.

This old man, he played ten,


He played knick-knack once again;

6
With a knick-knack paddywhack,
Give the dog a bone,
This old man came rolling home.
Try to make the program as short as possible by capturing recurring patterns. Define a
suitable function for each of those patterns.

thisOldMan :: String
thisOldMan = unlines [stanza n | n ← [1 . . 10]]
stanza :: Int → String
stanza n
= "This old man, he played " ++ numeral n ++ ",\n"
+
+ "He played knick-knack " ++ object n ++ ";\n"
+
+ "With a knick-knack paddywhack,\n"
+
+ "Give the dog a bone,\n"
+
+ "This old man came rolling home.\n"
numeral :: Int → String
numeral 1 = "one"
numeral 2 = "two"
numeral 3 = "three"
numeral 4 = "four"
numeral 5 = "five"
numeral 6 = "six"
numeral 7 = "seven"
numeral 8 = "eight"
numeral 9 = "nine"
numeral 10 = "ten"
object :: Int → String
object 1 = onMy "thumb"
object 2 = onMy "shoe"
object 3 = onMy "knee"
object 4 = onMy "door"
object 5 = onMy "hive"
object 6 = onMy "sticks"
object 7 = "up in heaven"
object 8 = onMy "gate"
object 9 = onMy "spine"
object 10 = "once again"
onMy :: String → String
onMy what = "on my " + + what

7
Exercise 1.3.
a) How many total functions are there that take one Boolean as an input and return
one Boolean? Or put differently, how many functions are there of type Bool → Bool ?
Define all of them. Think of sensible names.
Note: If you choose sensible names, then chances are high that your functions collide
with Haskell’s predefined functions in Prelude. Name your functions foo 0 instead of foo
to avoid that problem.

There are |B||A| total functions of type A → B , i.e. 4 functions of type Bool → Bool :

id 0 :: Bool → Bool
id 0 False = False
id 0 True = True
not 0 :: Bool → Bool
not 0 False = True
not 0 True = False
true 0 :: Bool → Bool
true 0 = True
false 0 :: Bool → Bool
false 0 = False

b) How many total functions are there that take two Booleans as an input and return
one Boolean? Or put differently, how many functions are there of type (Bool , Bool ) →
Bool ? Define at least four. Try to vary the definitional style by using different fea-
tures of Haskell, e.g. predefined operators such as || and &&, conditional expressions
(if . . then . . else . .), guards, and pattern matching.

There are |Bool||(Bool,Bool)| = |Bool||Bool|∗|Bool| = 22∗2 = 16 different total functions


of type (Bool , Bool ) → Bool , e.g.

and 0 :: (Bool , Bool ) → Bool


and 0 (a, b) = a && b
or 0 :: (Bool , Bool ) → Bool
or 0 (a, b) = if a then True else b
xor 0 :: (Bool , Bool ) → Bool
xor 0 (a, b)
|a = not b
| otherwise = b
implies 0 :: (Bool , Bool ) → Bool
implies 0 (True, False) = False
implies 0 ( , ) = True

c) What about functions of type Bool → Bool → Bool ?

Function types are right-associative: Bool → Bool → Bool is Bool → (Bool → Bool ).
 |Bool| 2
So there are |Bool → Bool||Bool| = |Bool||Bool| = 22 = 16 functions.

8
Exercise 1.4 (Skeleton: Char.hs). Haskell’s Strings are really lists of characters i.e.
type String = [Char ]. Thus, quite conveniently, all of the list operations are applicable
to strings, as well: for example, map toLower "Ralf" =⇒ "ralf". (Recall that map takes
a function and a list and applies the function to each element of the list.)
a) Define an equality test for strings that, unlike ==, disregards case, e.g. "Ralf" ==
"raLF" =⇒ False but equal "Ralf" "raLF" =⇒ True.

equal :: String → String → Bool


equal s1 s2 = map toLower s1 == map toLower s2

b) Define predicates
isNumeral :: String → Bool
isBlank :: String → Bool
that test whether a string consists solely of digits or white space. You may find the
predefined function and :: [Bool ] → Bool useful which conjoins a list of Booleans e.g.
and [1 > 2, 2 < 3] =⇒ False and and [1 < 2, 2 < 3] =⇒ True. For your convenience, the
skeleton file already imports Data.Char 2 .

isNumeral = and ◦ map isDigit — even shorter: all isDigit


isBlank = and ◦ map isSpace

c) Implement the Caesar cipher shift :: Int → Char → Char , e.g. shift 3 maps ’A’ to
’D’, ’B’ to ’E’, . . . , ’Y’ to ’B’, and ’Z’ to ’C’. Try to decode the following message
(map is your friend).
msg = "MHILY LZA ZBHL XBPZXBL MVYABUHL HWWPBZ JSHBKPBZ "
+
+ "JHLJBZ KPJABT HYJHUBT LZA ULBAYVU"

shiftForwards :: Char → Char


shiftForwards ’Z’ = ’A’
shiftForwards c = succ c
shiftBackwards :: Char → Char
shiftBackwards ’A’ = ’Z’
shiftBackwards c = pred c
shift :: Int → Char → Char
shift ’ ’ = ’ ’
shift n c
|n >0 = shift (n − 1) (shiftForwards c)
|n <0 = shift (n + 1) (shiftBackwards c)
| otherwise = c

map (shift 19) msg =⇒ "FABER EST SUAE QUISQUE FORTUNAE APPIUS "
++ "CLAUDIUS CAECUS DICTUM ARCANUM EST NEUTRON"

2
This provides you some useful functions, see http://hackage.haskell.org/package/base/docs/
Data-Char.html

9
Alternatively, you can use ord :: Char → Int and chr :: Int → Char . But be careful
with wrapping around from Z to A.

Exercise 1.5. For each of the following types, find an expression that has the given type.
You can verify your solution using the compiler: Open the GHCi and type :t expression
to see the type of expression. Note that Haskell infers the most general type for that
expression, possibly containing type classes. If Haskell outputs Num a => ... just imagine
all as in the type are replaced by Integer.

• Integer
• Integer → Integer
• Integer → Integer → Integer
• (Integer , Integer ) → Integer
• Integer → (Integer , Integer )
• (Integer → Integer ) → Integer
• [Integer ] → Integer
• a→a
• (b → c) → (a → b) → a → c

10

You might also like