Question 1: Higher-Order Functions

1a)

Question

What are higher-order functions and why are they so common in Haskell?

1b)

Question

Give the type signature and an explanation of the behaviour of the foldr higher-order function on lists.

foldr :: (a -> b -> b) -> b -> [a] -> b

The foldr function takes a binary operation, an initial value, and a list. It applies the binary operation to each element of the list and the result of folding the rest of the list, starting from the right with the initial value.

1c)

Question

Define a Haskell function twice :: (a->a)-> a -> a which applies the function (supplied as first parameter) two times to the subsequent parameter value. For instance, twice (+1) 0 would evaluate to 2.

1d)

Question

Now consider how to generalize the function twice to a function ntimes, which repeatedly applies a function (supplied as a parameter) multiple times. The type signature is: ntimes :: (a->a) -> Int -> a -> a. For example, ntimes (+2) 5 0 evaluates to 10 and ntimes tail 3 [1..4] evaluates to [4]. Write a Haskell definition for this ntimes function. You may assume the supplied integer value is non-negative. If the integer value is 0 then the behaviour is same as the identity function.

ntimes :: (a->a) -> Int -> a -> a
ntimes f 0 x = x 
ntimes f n x = ntimes f (n-1) (f x)

1e)

Question

Study the blowup function definition below. What happens if we evaluate blowup 42 at the GHCi interactive prompt, and why?

blowup :: Integer -> Integer
blowup n = n + blowup $ n+1

1f)

Question

Now suppose we evaluate ntimes blowup 0 42 at the GHCi interactive prompt. Explain why this evaluation terminates immediately with the result 42.

Question 2: Maps (Dictionaries) and Types

2a)

It is a typeclass (0.5 mark) constraint (0.5 mark). It expresses some behavioural constraint on the relevant polymorphic type variable (1 mark). For example, Eq a => a -> a means that the type denoted by a must be an instance of the Eq typeclass (1 mark).

2b)

Question

Consider using a list of (key, value) pairs in Haskell to represent an associative data structure, like a Python dictionary. Given generic type variables k for the key type and v for the value type, a potential type for the lookup function is given below: lookup :: [(k,v)] -> k -> Maybe v (i) Which constraint should we add to the lookup function type, and why?

To allow key comparisons (1 mark) we would prepend typeclass constraint Eq k => (1 mark) to the type. Also accept Ord for comparisons.

lookup :: Eq k => [(k,v)] -> k -> Maybe v
lookup myList key =
	if res then Just $ snd $ head res
	else Nothing
	where 
		res = filter (\(k, _) -> k == key) myList
 

2c)

Question

Why might a list of tuples be an inappropriate representation for an associative data structure like a dictionary?

2d)

Question

How would you define a type alias in Haskell for the [(k,v)] data structure when it is used to implement a dictionary?

Question 3: Monads

3a)

Question

Give the precise type for the bind function (>>=) in the Comp monad.

(>>=):: (Comp a)-> (a -> Comp b)-> (Comp b)

1 mark for each subtype in brackets (x3), and 1 mark for correct ‘shape’ with function arrows. Only 1 mark overall for the general bind type (in terms of Monad m rather than Comp).

3b)

Abstract

Suppose you are given two functions: primes :: Int -> Int and fibs :: Int -> Int which compute the nth prime number and nth fibonacci number respectively. These are compute-intensive, long-running functions for large values of n.

(i) Imagine a function funnysum which takes an Int value n then computes the sum of the nth prime and the nth Fibonacci number, returning this sum value in the Comp monad. What is the type signature of the funnysum function?

3c)

Question

Discuss possible motivations for using the Comp monad.

We might use Comp for long-running computations, perhaps executing them in parallel on different threads. This is like Futures or Promises in other languages.

Comp allows ordering of computations, controlled sequencing. It is precisely a ‘strict identity monad’.