Solutions to the Problem Sheet for LI Functional Programming - Week 2
Polymorphism
Find out the types of the following functions. Decide if they are polymorphic.
Function Type Polymorphic fst
(a, b) -> a
yes (++)
[a] -> [a] -> [a]
yes not
Bool -> Bool
no head
[a] -> a
yes tail
[a] -> [a]
yes id
a -> a
yes Explain, in your own words, what the function
zip
does. In the expressionzip ['x', 'y'] [False]
, what are the type variablesa
andb
ofzip :: [a] -> [b] -> [(a, b)]
instantiated by?The function zip traverses the two lists simultaneously while returning the pairs of the elements it encounters in a new list. If the lists are not the same length, the result will have the length of the shorter list. In the example, we have
a = Char
andb = Bool
.Find a polymorphic function in the GHC standard library whose type contains 3 type variables or more.
Examples are
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
andflip :: (a -> b -> c) -> b -> a -> c
.Read Section 3.7 of Programming in Haskell. Compare the types of the examples given there with the types
ghci
indicates.The only one which differs is
length :: Foldable t => t a -> Int
which is generalized from just the type[a]
of lists to arbitrary members of theFoldable
typeclass.
Types and Typeclasses
Run, and understand, the following examples
Expression Result Explanation False == 'c'
Error The left side has type Bool
while the right has typeChar
False == True
False
False == not
Error The left side had type Bool
while the right has typeBool -> Bool
False == not True
True
not == id
Error No instance of Eq
forBool -> Bool
[not] == [ (id :: Bool -> Bool) ]
Error No instance of Eq
forBool -> Bool
On type classes
Find all the basic instances of the type class
Bounded
that are defined in the GHC Prelude (the libraries that are loaded when startingghci
, without importing any additional libraries). Find out whatminBound
andmaxBound
are for each of the instances.Type minBound maxBound Word
0
18446744073709551615
Ordering
LT
GT
Int
-9223372036854775808
9223372036854775807
Char
\NUL
'\1114111'
Bool
False
True
What type classes do the type classes
Fractional
,Floating
,Integral
extend? What functions to they provide?Typeclass Extends Provides Fractional
Num
(/) :: a -> a -> a
recip :: a -> a
fromRational :: Rational -> a
Floating
Fractional
pi :: a
exp :: a -> a
log :: a -> a
... Integral
Real a
,Enum a
quot :: a -> a -> a
rem :: a -> a -> a
div :: a -> a -> a
... Another type class:
Which type class defines the function
enumFromTo
?Enum
Evaluate
enumFromTo
on elements of each instance of that type class.Type Expression Result Word
enumFromTo (1 :: Word) 3
[1,2,3]
Ordering
enumFromTo LT GT
[LT,EQ,GT]
Integer
enumFromTo (-1 :: Integer) 2
[-1,0,1,2]
Int
enumFromTo (3 :: Int) 5
[3,4,5]
Char
enumFromTo 'c' 'g'
"cdefg"
Bool
enumFromTo True False
[]
()
enumFromTo () ()
[()]
Float
enumFromTo (1.5 :: Float) 2.5
[1.5,2.5]
Double
enumFromTo (1.5 :: Double) 2.5
[1.5,2.5]
Explain the different output between
:type enumFromTo 4 8
and:type enumFromTo 4 (8 :: Int)
.The former gives
enumFromTo 4 8 :: (Enum a, Num a) => [a]
and we see that the type is still polymorphic, since the type of both4
and8
is ambiguous. The latter specifies that8 :: Int
so that Haskell instantiates the type varialbea
toInt
.
Functions in Haskell
Using the functions
removeLast
andremoveElem
from Handout - Functions, write a function that removes both the first and the last element of a list.removeFirstAndLast :: [a] -> [a]
removeFirstAndLast = reverse . tail . reverse . tailUsing guarded equations, write a function of type
Int -> Int -> Bool
that returnsTrue
if the first argument is greater than the second and less than twice the second.betweenNand2n :: Int -> Int -> Bool
betweenNand2n k n | k > n && k < 2 * n = True
| otherwise = FalseWrite a function to pair each element of a list with its index.
withIndex :: [a] -> [(Int,a)]
withIndex l = zip [0 .. length l - 1] l
withIndex' :: [a] -> [(Int,a)]
withIndex' l = [ (i, l !! i) | i <- [0 .. length l-1] ]Write a function which returns the reverse of a list if its length is greater than 7. Now modify the function so that the cutoff length is a parameter.
reverse7 :: [a] -> [a]
reverse7 l = if (length l > 7) then reverse l else l
reverse7guard :: [a] -> [a]
reverse7guard l | length l > 7 = reverse l
| otherwise = l
reverseParam :: Int -> [a] -> [a]
reverseParam n l | length l > n = reverse l
| otherwise = lWrite a function
orB :: Bool -> Bool -> Bool
that returnsTrue
if at least one argument isTrue
.orB :: Bool -> Bool -> Bool
orB True True = True
orB True False = True
orB False True = True
orB False False = False
orB' :: Bool -> Bool -> Bool
orB' True _ = True
orB' _ True = True
orB' _ _ = FalseWrite a function
swap :: (a, b) -> (b, a)
that swaps the elements of a pair.swap :: (a,b) -> (b,a)
swap (x,y) = (y,x)Define three variants of a function
third :: [a] -> a
that returns the third element in any list that contains at least this many elements, usinghead
andtail
thirdHeadTail :: [a] -> a
thirdHeadTail = head . tail . taillist indexing
!!
thirdIndex :: [a] -> a
thirdIndex l = l !! 2pattern matching
thirdMatching :: [a] -> a
thirdMatching (_:_:x:_) = x
Define a function
safetail :: [a] -> [a]
that behaves like tail except that it maps[]
to[]
(instead of throwing an error). Usingtail
andisEmpty :: [a] -> Bool
. Definesafetail
usinga conditional expression
isEmpty :: [a] -> Bool
isEmpty [] = True
isEmpty _ = False
safeTailCond :: [a] -> [a]
safeTailCond l = if isEmpty l then [] else tail lguarded equations
safeTailGuard :: [a] -> [a]
sageTailGuard l | isEmpty l = []
| otherwise = tail lpattern matching
safeTailMatch :: [a] -> [a]
safeTailMatch [] = []
safeTailMatch (_:xs) = xs