Question 1: Maps (Dictionaries) and Types

1a)

Question

What is the role of , i.e. the ‘fat arrow’ notation, in a Haskell type? Explain using a simple example if necessary.

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).

1b)

Abstract

(b) 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?

1c)

Question

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

1d)

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 2: Algebraic Datatypes and Type Inference

Abstract

Given the following type and expression:

tree1 :: (Int,[a])
tree1 = (0,[(1,[]),(2,[(3,[])]),(4,[(5,[(6,[])])])])

(i) Type checking this code gives a type error. What is the reason for the type error?

The type variable ‘a’ can only be bound to one concrete type. The types of [],[(3,[])],[(5,[(6,[])])] are not the same.

data Tree1 = T1 (Int, [( Int , [(Int, [(Int, [Int] )] )] )] )
res = let (v0,[(v1,[]),(v2,[(v3,[])]),(v4,[(v5,[(v6,[])])])]) = tree1 in 
		v0+v1+v2+v3+v4+v5+v6

21

2b)

(b) Given the following code:

makeTree0 = foldl' (\acc elt -> (elt,[acc])) (0,[]) [1 .. ]

(i) What is the type-level problem with this code?

(ii) Propose a recursive, non-polymorphic algebraic datatype Tree2 with constructor T2 such that the following code is correct:

makeTree1 = foldl' (\acc elt -> T2 (elt,[acc])) (T2 (0,[])) [1 .. ]

It hangs because we attempt to strictly left-fold an infinite list and constructing that list never finishes.

Suppose we modify the code to use foldr:

makeTree2 = foldr (\acc elt -> T2 (elt,[acc])) (T2 (0,[])) [1 .. ]

(iv) What is wrong with this code?

Arguments acc and elt need to be swapped

(v) Provide the correct code for makeTree2 (i.e. the minimal change to the expression to fix the type error, while still using foldr)

It prints forever because of the lazy evaluation of the foldr and because each iteration applies f to the next value and the result of the fold on the rest of the list. So on every iteration, the type constructor and the integer value are known and will be printed; the content of the list is iteratively printed.

Question 3: Monads

3a)

Abstract

A monad consists of a type m a, the functions return and bind (also written >>=), and the optional >> operator. Given the following type:

data This a = This a

(i) Complete the implementation of return.

return = ...

(ii) Complete the implementation of >>=.

(>>=) (This x) f = ...

(iii) With the given implementation of >>=, and assuming the definition for f is:

f = This . id

What is the type of f?

f :: a -> ...

3b)

Abstract

(b) A monad must also satisfy the three monad laws. Assume return and >>= are defined as above.

(i) Complete the expression so that the 1st monad law (left identity) holds:

\x -> (This x >>= return)  ...

(ii) Complete the expression so that the 2nd monad law (right identity) holds:

return x >>= ... This x

(iii) Complete the expression so that the 3rd monad law (associativity) holds:

(This x >>= This) >>= This ... >>= (\x ... This x ... This)

3c)

Given following type:

data CouldBe a = Really a | Only a | None

(i) Complete the implementations of return and >>= so that the three monad laws are satisfied.

return = ...
None >>= f = ...
(Really ...) >>= f = ... x
(... x) >>= f ... f x

This is a drag and drop question with possible answers from [CouldBe, Really, Only, None, f, x, a, =, >>= ]

3d)

Abstract

Given following code which defines a type UMaybe and makes it an instance of the Monad typeclass with the given definitions of return and >>=. We define a function uLookup which takes a string and returns values of type UMaybe. In the function uCheck we use do-notation to combine calls to this function.

data UMaybe a = UJust a | UUnknown | UNothing deriving Show
instance Monad UMaybe where
  return = UJust
  (>>=) UNothing f = UNothing
  (>>=) UUnknown f = UUnknown
  (>>=) (UJust x) f = f x
 
uLookup :: String -> UMaybe Int
uLookup "1" = UJust 2
uLookup "2" = UUnknown
uLookup "3" = UJust 4
uLookup "4" = UJust 5
uLookup _ = UNothing
 
uCheck v0 = do
  v1 <- uLookup v0
  v2 <- uLookup (show v1)
  v3 <- uLookup (show v2)
  return (v1,v2,v3)
 
main :: IO ()
main = print $ uCheck "1"

(i) What is the value of v1?

uLookup (show v1) = UUnknown

`uCheck “1” = UUnknown¦

uCheck :: String -> UMaybe (Int,Int,Int)