You are on page 1of 4

Prof.aa Dr. J. Giesl Notes: Please solve these exercises in groups of two!

Functional Programming SS12 Exercise Sheet 2 (due 04.05.2012) M. Brockschmidt, F. Emmes

The solutions must be handed in directly before (very latest: at the beginning of ) the exercise course on Friday, 04.05.2012, 10:00, in lecture hall AH 2. Alternatively you can drop your solutions into a box which is located right next to Prof. Giesls oce (until the exercise course starts). Please write the names and immatriculation numbers of all (two) students on your solution. Also please staple the individual sheets!

Exercise 1 (Data types):

(2 + 1 + 1 + 2 + 2 = 8 points)

a) Give a denition for a data type Peano that encodes the natural numbers in Peano notation, i.e., it encodes 0 as Zero, 1 as (Succ Zero), and so on. Furthermore, write a function fromInt :: Int -> Peano that converts an Int value to your new data type. It may behave arbitrarily on negative numbers. For example, fromInt 2 should yield Succ (Succ Zero). b) We consider multitrees, i.e., trees in which each node may have an arbitrary number of successors: 72

28

23

77

42

Here, we see a tree with ve elements. The root of the tree stores the value 72 and has one child containing 28. That node in turn has three successors, storing 23, 77 and 42, respectively. Give a denition for a data type MTree a with two constructors Node and Empty. Each Node should store a value of type a and a list of successor nodes. c) Give a term of type MTree Int that encodes the example tree from above. d) Write a function sumTree :: (Num a) => MTree a -> a that gets a tree as argument and sums up the values in its nodes. For the example tree from above, this would yield 242. e) Write a function convertIntTreeToPeano :: MTree Int -> MTree Peano that walks through a tree and replaces each Int value in the nodes by the corresponding Peano value obtained using fromInt from a). Your function may behave arbitrarily on negative numbers.

Exercise 2 (Type Classes):

(2 + 1 + 3 + 1 + 2 = 9 points)

In this exercise, you should implement a Haskell data-declaration and several functions to work with polynomials over integers. a) A polynomial is either a variable, represented by a value of type String, a constant number of type Integer1 , or the addition or multiplication of two polynomials. Dene an algebraic data type with four constructors, by writing a data declaration Polynomial. With your declaration, the following should be a valid Haskell expression of type Polynomial.
1 In

contrast to Int, the type Integer represents arbitrary large integer numbers.

Functional Programming SS12 Exercise Sheet 2 (due 04.05.2012) Add (Mul (Var "x") (Const 3)) (Mul (Var "y") (Var "y")) Since we are interested in creating our own String representation of polynomials, please do not label the data declaration with deriving Show. b) Write a Show instance declaration for your Polynomial data type. You only need to give a denition for the show function (which has the type Show a => a -> String). A variable should be shown as just its name and a constant as just its value. Always enclose addition and multiplication in parentheses. For example, the expression above should be mapped to ((x*3)+(y*y)). Hints: You can get information about types, type classes, and constructors, by using the command :info in GHCi. For example :info Show lists functions and instances of the Show type class. Since a String is just a list of Chars, the function (++) can also be used to concatenate Strings. c) Write an Eq instance declaration for your Polynomial data type. Here, you only need to implement the function (==) :: Eq a => a -> a -> Bool. This method should compare two polynomials for syntactic equivalence. Hence, Add (Const 0) (Const 1) == Const 1 should yield False. Also, write an instance declaration for the type class Num, but only implement the functions fromInteger :: (+) :: (*) :: Num a => Integer -> a, Num a => a -> a -> a, and Num a => a -> a -> a.

Here, (+) and (*) should add or multiply Polynomials, while fromInteger should return a Polynomial representing the given integer number, for example fromInteger 3 == Const 3. To avoid warnings from the Haskell compiler, you can mark the functions abs and signum as deliberately undened by inserting abs = undefined signum = undefined into the instance declaration. Remarks: The function fromInteger is used to convert Integer numbers into Polynomials (or any other type that is an instance of Num). This is especially useful, since number literals like 3 occurring in a Haskell le are interpreted as if the programmer had written fromInteger 3. Hence, the meaning of a literal 3 depends on the instance of the type class Num that is correct in this context. In languages like Java, only the types of the arguments determine which implementation of a function is evaluated. In contrast, in Haskell, also the expected type of the result of a function can be used to determine which implementation of the function to evaluate. To make sure that the Haskell interpreter chooses the right instance for Num, when entering entering an expression in GHCi, you need to state its expected type explicitly by appending :: Polynomial or :: Integer, etc. Main> 3 + 2 :: Integer 5 Main> 3 + 2 :: Polynomial (3+2) Main> sum [1,2,3] :: Polynomial (((0+1)+2)+3) In the last example, the type of sum is Num a => [a] -> a. Since we expect the result of the expression to be a Polynomial, the argument must be a list of Polynomials. Hence, the implementation of fromInteger from the instance Num Polynomial is chosen to convert the literals 1, 2, and 3.

Functional Programming SS12 Exercise Sheet 2 (due 04.05.2012) d) To allow comfortable parsing of polynomial expressions, import the module PolyParser (which you can download from the homepage as PolyParser.hs) by inserting import PolyParser at the top of your le. The function to parse polynomial expressions, parsePoly is of type (HasVariables a, Num a) => String -> a. The type class HasVariables, contained in PolyParser.hs, is declared as class HasVariables a where fromVariable :: String -> a and represents types that can contain variables named by Strings. Write an HasVariables instance declaration for the data type Polynomial. Here, implement the function fromVariable such that it maps a String s to Var s (of type Polynomial). When loading your program into GHCi, you are now be able to parse polynomials: Main> parsePoly "x*x+3*(y+x)" :: Polynomial ((x*x)+(3*(y+x))) e) When dealing with a polynomial, one is often interested in its derivative w.r.t. some variable. Implement the function derivative :: String -> Polynomial -> Polynomial, which gets the name of a variable x and a polynomial p and computes the derivative of p w.r.t. x. You do not need to make sure that the resulting polynomial is simplied, only that it is correct. For example derivative "x" (parsePoly "x*y") might return ((1*y)+(x*0)).

Exercise 3 (Lambda calculus):

(2 + 1 + 2 = 5 points)

In this exercise, an implementation of the pure Lambda calculus, which will be discussed in depth in Chapter 3 of the lecture, will be constructed. For a set of variables V , the set of lambda terms consists of all variables x V applications (t1 t2 ), where t1 , t2 abstractions x.t, where x V is the bound variable and t 2 To represent lambda terms in Haskell, we use the following data type denition (where we use Integers to identify our variables)3 : type VarName = Integer data LTerm = LVar VarName | LApp LTerm LTerm | LAbstr VarName LTerm a) The free variables free(t) of a lambda term t are those variables that are not explicitly bound in an enclosing lambda abstraction. This set is dened inductively as follows: free(x) = {x} for x V free((t1 t2 )) = free(t1 ) free(t2 ) for t1 , t2 free(x.t) = free(t) \ {x} For example, for t = (x.x y.(x y )), we have free(t) = {x}, as x is not bound in y.(x y ). Write a function free :: LTerm -> [VarName] that returns the free variables in a lambda term as a list, i.e., variables may be duplicated.
2 This corresponds 3 On our webpage,

to Haskell's \x -> t syntax, describing a function with one argument named x. you can download Lambda.hs containing these declarations and a parser that allows easy input of test terms. By writing import Lambda at the top of your solution, you can import these denitions. Then, parseLambda "\\x1.(x1 x2)" returns the internal representation of x1.(x1 x2).

Functional Programming SS12 Exercise Sheet 2 (due 04.05.2012) b) Write a function freshVarName :: [VarName] -> VarName that takes a list of variable names vs and returns a variable name that does not occur in that list. For example, freshVarName [1,2,7] could return 8. Hints: Use the function maximum :: (Ord a) => [a] -> a which returns the maximal value in a list. Ensure that you also return a variable name when the input list is empty. c) To implement the lambda calculus, we need to instantiate variables in lambda terms using substitutions. A substitution [x/t] can be applied on a term r by replacing every free occurrence of the variable x by the term t. For example, for t from above, t[y/x] = t (as y is not free in t) and t[x/(z z )] = (x.x y.((z z ) y )).4 The le Lambda.hs contains a denition for the function subst :: LTerm -> VarName -> LTerm -> LTerm (in comments, as it does not work without the functions from a) and b)) such that subst r x t yields the term r[x/t], where all free occurrences of x in the term r have been replaced by t. We can now implement the application of lambda abstractions, i.e., evaluating a term (x.t1 t2 ) to t1 [x/t2 ]. To handle cases where a lambda term does not have this shape, we use the data type Maybe, which either is Nothing or Just r, where r is the result: data Maybe a = Nothing | Just a deriving ( Eq , Ord , Read , Show )

Copy subst to your solution and implement a function eval that for (x.t1 t2 ) returns Just t1 [x/t2 ] and Nothing in all other cases.

4 When

performing substitutions, one sometimes needs to rename variables to ensure that the free variables in t do not become bound by an enclosing lambda extraction by accident, i.e., t[x/(y y )] = (x.x y .((y y ) y )). The provided implementation does this.

You might also like