Midterm Sample Solutions
--=============
-- PROBLEM 1 a)
--=============
-- an enumeration type
data MyColor = Red | Green | Blue
deriving (Enum, Show)
-- a fancy example (not required)
mycols0 = map (toEnum::Int->MyColor) [fromEnum Red .. fromEnum Blue]
-- a product type (defines a new type: data constructor = "Pers")
data Person1 = Pers String Int
-- a product type (doesn't define a new type, but just type synonyms)
type Person2 = (Name, Age)
type Name = String
type Age = Int
-- a list type (new user-defined list type)
data MyPolyList1 a = EmptyList | Cons a (MyPolyList1 a)
-- a list type (type synonym)
type MyPolyList2 a = [a]
-- a list type (example type and value declaration for a constant)
mylist0 :: [Int]
mylist0 = [1..10]
-- a record (tuple) type
-- (same as product type.... here polymorphic for a change...)
data MyRecord a = Rec a [a]
-- a recursive type
-- (same as MyPolyList1 above)
-- a non-recursive type
-- (same as Person1/2 above)
-- an algebraic type
data XML = EmptyXML | Leaf Tag | Node Tag [XML]
type Tag = String
{-
=============
PROBLEM 1 (b)
=============
"MyPolyList1 a" from above is an example of a
polymorphic type. The type variable "a" stands for a set of types.
When a value of type "MyPolyList1 a" is constructed (either at
compile-time, e.g.
list0 = Cons 1 (MyPolyList1 EmptyList)
or at runtime, the type variable "a" will become instantiated with a
concrete type, say "Int". More interesting than constants like list0
are in fact polymorphic functions that work on polymorphic types
(e.g., the length of a list can be computed in the same way for all
types "a").
=============
PROBLEM 1 (c)
=============
in both cases, the result type is arbitrary. The difference is in the
index/key type:
regular array: the index/key type is (subrange of) Integer or some
other enumerated type (e.g., MyColor above)
associative array: the index/key type is any type (often "String")
Note: a common way to implement associative arrays is via hashes
=============
PROBLEM 1 (d)
=============
Arrays can be seen as (*are*) finite functions:
E.g. the array arr :: Integer -> Char
arr[1] = 'f', arr[2] = 'o', arr[3] = 'o'
and the function g :: Integer -> Char
g(1) = 'f', g(2) = 'o', g(3) = 'o'
obviously denote the same function.
The other way round: finite functions can be implemented as array.
=========
PROBLEM 2
=========
(a) add1 3 4
type : Integer
value : 7
(b) add1 -1
type : Integer -> Integer ( function )
value : decrement function ( \x. x-1 )
(c) add2 -1
compile time error.
Because this is an uncurried function, and it requires two argument as
input explicitly.
=========
Problem 3
=========
(a) leftmost outermost reduction
double ( second ( double 2 ) ( double 3 ) )
=> ( second ( double 2 ) ( double 3 ) ) + ( second ( double 2 ) ( double 3 ) )
=> ( double 3 ) + ( second ( double 2 ) ( double 3 ) )
=> ( 3 + 3 ) + ( second ( double 2 ) ( double 3 ) )
=> 6 + ( second ( double 2 ) ( double 3 ) )
=> 6 + ( double 3 )
=> 6 + ( 3 + 3 )
=> 6 + 6
=> 12
(b) f 4 6 = f 6 4 = f 4 (6-4) = f 4 2 = f 2 (4-2) = f 2 2 = 2
f 7 12 = f 12 7 = f 7 (12-7) = f 7 5 = f 5 (7-5) = f 5 2 = f 2 (5-2)
= f 2 3 = f 3 2 = f 2 (3-2) = f 2 1 = f 1 (2-1) = f 1 1 = 1
(c) f computes the greatest common denominator (GCD) of the two arguments.
f 0 3 = f 3 0 = f 0 (3-0) = f 0 3 ....
It will loop forever!
=========
PROBLEM 5
=========
a)
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x : map f xs
b)
Using a helper function:
inc x y = 1 + y
Thus the function that calculates the length of the list:
length xs = foldr (inc) 0 xs
OR
length = foldr (inc) 0
=========
PROBLEM 6
=========
a)
20
/ \
10 5
/ \
1 3
b)
The types of foo and mytree0 are:
foo :: MyTree a -> [a]
mytree0 :: MyTree Int
c)
[ 1, 3, 10, 5, 20 ]
The function returns a list of nodes of the tree in postorder.
-}
Bertram Ludaescher
Last modified: Tue Feb 27 02:34:38 PST 2001