> import qualified Functional.Exercise.Exercise2 as Ex
1) Given the following function definitions, give an equivalent definition using lambda functions.
>func1::Bool->Integer->Integer->Integer
>func1bnm=ifnotbthennelsem
>
>func2::Integer->Integer
>func2n=n+n
>
>func3::Integer->Integer->Integer
>func3nm=n+m*m
>func1Lambda::Bool->Integer->Integer->Integer
>func1Lambda=\bnm->ifnotbthennelsem
>
>func2Lambda::Integer->Integer
>func2Lambda=\n->n+n
>
>func3Lambda::Integer->Integer->Integer
>func3Lambda=\nm->n+m*m
For example, for the function
>func::Integer->Bool->Integer
>funcnb=ifbthennelse42
an equivalent definition using a lambda function looks as follows.
>funcLambda::Integer->Bool->Integer
>funcLambda=\nb->ifbthennelse42
2) Given the `IntList` type from the lecture notes about "Recursion".
data IntList where
Nil :: IntList
Cons :: Integer -> IntList -> IntList
Define the following higher-order functions `mapList` and `filterList` that follow the same abstraction pattern as the functions we defined for `CoordMap` in the lecture.
3) Using these definitions of `mapList` and `filterList`, define the following functions that increment all `Integer` values of a given `IntList` and keep the `Integer`-values that are greater than 5, respectively.
>incList::IntList->IntList
>incListiList=mapListfunciList
>wherefuncx=x+1
>greater5List::IntList->IntList
>greater5ListiList=filterListprediList
>wherepredx=x>5
The functions should behave as follows.
> incList (Cons 1 (Cons 2 (Cons 3 Nil)))
Cons 2 (Cons 3 (Cons 4 Nil))
> greater5List (Cons 2 (Cons 12 (Cons 5 Nil))
Cons 12 Nil
In a second step use lambda functions instead of a local function definition.
>incList'::IntList->IntList
>incList'iList=mapList(\x->x+1)iList
>greater5List'::IntList->IntList
>greater5List'iList=filterList(\x->x>5)iList
4) Given the `Field` data type from the last exercises.
data Token where
Blank :: Token
Block :: Token
data Row where
EmptyR :: Row
ARow :: Token -> Row -> Row
data Field where
EmptyF :: Field
AField :: Row -> Field -> Field
We implemented functions `replaceTokenInRow` and `replaceTokenInField`. Reimplement these functions using the higher-order helper functions `mapRow` and `mapField`. In order to avoid name clashes we imported the corresponding module qualified by using `Ex`.
<<<------------- Exercises corresponding to lecture on 16/12/19 ------------->>>
5) Now that we know about polymorphic structures, let us redefine the `Field` type as follows.
>-- type Field token = [[token]]
>typeFieldtoken=[]([]token)
Here, instead of reusing the `Token`s defined in the last exercise, we use a type parameter in order to use the type synonym `Field` with abritrary values.
Reimplement the function `replaceTokenInField` once more using the predefined higher-order function `map` that works an arbitrary lists; note that for this concrete example, we reuse `Ex.Token`.
6) We also redefined `CoordMap` using polymorphic lists and pairs.
>-- type Coord = (Int,Int)
>typeCoord=(,)IntInt
>-- type Coords = [Coord]
>typeCoords=[]Coord
Based on this type synonym we define a type to represent `Coordinate`s as keys and arbitrary tokens as values in order to describe the positions of such tokens. A list of such pairs describes a figure.
>-- type Figure token = [(Coord, token)]
>typeFiguretoken=[]((,)Coordtoken)
Here, we again use a type parameter `token` to use `Figure` with an abitrary type.
Using this type, we can visualise, for example, the following figure.
Define a function `lookupCoord` that checks if a given figure contains the specific coordinate: if yes the function should yield the associated token and `Nothing` otherwise.
Observe that these definitions following the same scheme as for lists: a mapping function applies its functional argumt to each element of the structure (in case of trees, the elements occur in the `Leaf`-constructor); a folding function describes how to transform a structure to an arbitrary type by specifying the function to replace the constructors with.
Now define the following functions using `mapTree` and `foldTree`, respectively.
>negateTree::TreeBool->TreeBool
>negateTreet=mapTreeelemFt
>where
>elemFb=notb
>
>sumTree::TreeInt->Int
>sumTreet=foldTreeleafFnodeFt
>where
>leafFi=i
>nodeFsum1sum2=sum1+sum2
>
>values::TreeInt->[Int]
>valuest=foldTreeleafFnodeFt
>where
>leafFi=[i]
>nodeFlist1list2=list1++list2
3) The `foldList` function we defined in the lecture is predefined as `foldr :: (a -> b -> b) -> b -> [a] -> b` in Haskell. Reimplement the function `countElem` given in the lecture using `foldr`.
> countElem :: [] Int -> Int -> Int
> countElem [] elemToFind = 0
> countElem (val:list) elemToFind = if val == elemToFind
> then 1 + countElem list elemToFind
> else countElem list elemToFind
>countElem::[]Int->Int->Int
>countElemlistelemToFind=foldrconsFemptyFlist
>where
>consFicount=ifi==elemToFindthencount+1elsecount
>emptyF=0
4) Given the following data type to represent arithmetic expression consisting of numeric values, an addition or multiplication.
>dataExprwhere
>Num::Int->Expr
>Add::Expr->Expr->Expr
>Mult::Expr->Expr->Expr
Give three exemplary values for arithmetic expressions that represent the expression given in the comment above.
>-- 1 + (2 * 3)
>expr1::Expr
>expr1=Add(Num1)(Mult(Num2)(Num3))
>
>-- (1 + 2) * 3
>expr2::Expr
>expr2=Mult(Add(Num1)(Num2))(Num3)
>
>-- (1 + 2) * (3 + 4)
>expr3::Expr
>expr3=Mult(Add(Num1)(Num2))(Add(Num3)(Num4))
Define a function `value` that interpretes the `Expr`-data type by replacing the constructors `Add` and `Mult` with the concrete addition and multiplication operator.
>value::Expr->Int
>value(Numi)=i
>value(Adde1e2)=valuee1+valuee2
>value(Multe1e2)=valuee1*valuee2
For example, the function should yield the following result for the above expressions.
$> value expr1
7
$> value expr2
9
$> value expr3
21
Complete the signature for the mapping and folding function corresponding to the given type and implement these functions. The mapping function enables us to apply a function on the `Int` occurs in the `Num`-constructor. The folding function is a higher-order function that enables us to exchange the constructors of a given `Expr`-values with functions in order to compute a new value.
5) Define a function `repeatValue` that computes an infinite list containing the value given as argument.
>repeatValue::a->[]a
>repeatValuex=x:repeatValuex
Define a function `replicateValue` that takes an `n :: Int` as first argument and yields a list of length `n` containing the value given as second argument. Use `repeatValue` and `take` to define the function.
1. In Haskell `String`s are list of `Char`s. The following definitions should transform the given string "HelloWorld" such that it yields the string specified by the comment above. You are only allow to use generic list functions like `map`, `foldr`, `filter`, but no manual pattern matching, for the implementation.
>-- str1 "HelloWorld" = "HelloWorld!"
>str1::String->String
>str1str=foldr(:)"!"str
>
>-- str2 "HelloWorld" = "IfmmpXpsme"
>str2::String->String
>str2str=map(\ch->chr(ordch+1))str
>
>-- str3 "HelloWorld" = "HllWrld"
>str3::String->String
>str3str=filter(\ch->not(vowelch))str
>where
>vowelc=elemc"aeiou"
2. Implement a function `getInBounds :: Int -> Int -> IO Int` that reads a number from the user. If the value is not within the given bounds, the user needs to try again to type in a number that meets the bounds. The implementation should additionally behave as illustrated below.
$> getInBounds 12 16
Please type in a number between 12 and 16.
131
The number does not meet the given bounds, please try again.
13s
This input is not a number, please try again.
13
Hint: You should reuse `getNumber` and `inBounds` that we defined in previous lectures.
>getInBounds::Int->Int->IOInt
>getInBoundsminmax=putStrLn("Please type in a number between "++showmin++" and "++showmax++".")>>
>getNumber>>=(\n->
>ifinBoundsn(max,min)
>thenpuren
>elseputStrLn"The number does not meet the given bounds, please try again">>getInBoundsminmax)
>
>inBounds::Int->(Int,Int)->Bool
>inBoundsx(xMax,xMin)=(x<=xMax)&&(x>=xMin)
3. Implement a more general function `geStringWithCondition :: (String -> Bool) IO String` that reads a string from the user and only yield this value if the string obeys to the corresponding prediate. If the predicate does not hold, the user should be informed to try it again.
4. Implement an interactive number guessing game. The game `guessNumber` expects the "secret number" as argument and gives feedback for each guess and the game is completed, if the guessed number matches the secret. Otherwise the user gets feedback if the guess was "too small" or "too large".
Hint: Reuse the function `getNumber` from the lecture.
>guessNumber::Int->IO()
>guessNumbersecretNumber=
>putStrLn"Let's try to guess the number!">>
>gameLoop
>where
>gameLoop=getNumber>>=(\userGuess->
>ifuserGuess==secretNumber
>thenputStrLn"Congrats, you guessed the number!"
>elseifuserGuess<secretNumber
>thenputStrLn"Your guess is too small. Try again.">>gameLoop
>elseputStrLn"Your guess is too large. Try again.">>gameLoop)
A round might look like this! Note, that this is a two-player game: the user starting the game shouldn't be the one guessing the numbers ; )
$> guessNumber 421
Let's try to guess the number!
12
Your guess is too small. Try again.
100
Your guess is too small. Try again.
200
Your guess is too small. Try again.
300
Your guess is too small. Try again.
400
Your guess is too small. Try again.
500
Your guess is too large. Try again.
450
Your guess is too large. Try again.
425
Your guess is too large. Try again.
413
Your guess is too small. Try again.
420
Your guess is too small. Try again.
422
Your guess is too large. Try again.
421
Congrats, you guessed the number!
5. Give the types for the following expressions.
a) `map ((+) 1)`
b) `[(+) 1, (*) 2, div 3]`
c) `foldr (+)`
d) `filter ((>) 4)`
e) `map (*)`
a) [] Int -> [] Int
b) [Int -> Int]
c) Int -> [] Int -> Int
d) [] Int -> [] Int
e) [] Int -> [] (Int -> Int)
6. Which of these type signatures are valid for the function `map`.
7. We want to represent a set of `Int` values as function `Int -> Bool`, that is, the resulting `Bool` indicates if the argument passed is part of the set (for `True`) or not (for `False`).
>typeSet=Int->Bool
We can, for example, define the empty set as follows.
>empty::Set
>empty=\_->False
Since our representation of `Set` is a function, the empty set is the function that yields `False` for every argument: because no value is part of the empty set! That is, the representation of our function is based on the "lookup"-function (we used the first idea in the lecture (see `Misc.hs` for reference)).
The idea becomes more clear when we "inline" the type synonym `Set` (here we use an additional comment) and rename the `set`-variable to `isInSet` to indicate that this argument is a function that yields a boolean value (i.e., a predicate).
> isElem :: Int -> Set -> Bool
> -- isElem val set = set val
> -- isElem :: Int -> (Int -> Bool) -> Bool
> isElem val isInSet = isInSet val
>-- Yields `True` if the given `Int`-value is part of the `Set`, `False` otherwise.
>isElem::Int->Set->Bool
>isElemvalisInSet=isInSetval
Based on this representation, define the following functions.
You can also use the following function `fromList` to convert a list into a `Set` representation in order to test your implementation with "larger" sets. Note, that you need to implement `insert` first ; )