Now that i know a little more about haskell, I can go and refresh my memory about algorithms but the functional way. So, I came accross functional approach in haskell which does exactly that.
Here are the first exercises (focused on haskell for the moment).
Simple
Using a haskell interpreter, evaluate the following expressions (try to predict the result): (1+2) if (2 > 9) then "hello" else "bye" let x=(sqrt 16) in x+1
(1+2) - 3 if (2 > 9) then "hello" else "bye" - "bye" let x=(sqrt 16) in x+1 - 5.0
Interpreter:
*Ch1> 1 + 2 3 *Ch1> if (2 > 9) then "hello" else "bye" "bye" *Ch1> let x=(sqrt 16) in x+1 5.0
*
Define and load the following function:
fact 1 = 1fact n = n * fact (n-1)a) Using the interpreter, evaluate the expression
fact 5b) What happens when you try to evaluatefact 0? Alter the above definition to solve this definition. c) Modify your definition such that the value -1 is returned when an attempt is made to compute the factorial of a negative value.
a)
*Ch1> fact 5 120
b)
- the function does not terminate
 - alter:
 
fact :: Int -> Int fact 0 = 1 fact n = n * fact (n-1)
c) Compute factorial of a negative value must render -1:
fact :: Int -> Int fact n | n < 0 = -1 | n == 0 = 1 | otherwise = n * fact (n-1) *Ch1> fact 0 1 *Ch1> fact 1 1 *Ch1> fact 5 120 *Ch1> fact (-10) -1
wrong
What is wrong with the following expressions? Can you change them to make them valid?
1:2:3 [ [2,3] ++ [], [2,3]:[] ] "hello" : "world"
*Ch1> (1:2:3:[]) [1,2,3] *Ch1> [[[2,3] ++ []], ([2,3]:[])] [[[2,3]],[[2,3]]] *Ch1> "hello" ++ "world" "helloworld"
reverse
Given the following function:
f l = reverse (f' l []) where f' [] r = r f' (x:xs) r = (2*x) : (f' xs r)
What is the value of
f [1,2,3,4])? Check your answer with the haskell interpreter.
Answer step by step:
f [1,2,3,4] = reverse (f' [1,2,3,4] []) = reverse ((2*1) : (f' [2,3,4] [])) = reverse (2 : (2*2) : (f' [3,4] [])) = reverse (2 : 4 : (2*3) : (f' [4] [])) = reverse (2 : 4 : 6 : (4*2) : (f' [] [])) = reverse (2 : 4 : 6 : 8 : []) = [8,6,4,2]
Interpreter:
*Ch1> f [1..4] [8,6,4,2]
Predict
Try to predict the value of the following expressions:
[1,2,3] ++ [4]1:(2:(3:[4]))head [1,2,3]tail [1,2,3]drop 4 [1,2,3,4,5][1,2,3,4] !! 2
[1,2,3] ++ [4] -- [1,2,3,4] 1:(2:(3:[4])) -- [1,2,3,4] head [1,2,3] -- 1 tail [1,2,3] -- [2,3] drop 4 [1,2,3,4,5] -- [5] [1,2,3,4] !! 2 -- 3
functions
Write Haskell functions for: a) computing the average value of a list of numbers; b) selecting the middle element in a list (assuming an odd-length list).
a)
avg :: [Int] -> Int avg xs | null xs = 0 | otherwise = (sum xs) `div` (length xs) *Ch1> avg [1..10] 5 *Ch1> avg [] 0
b)
mdl :: [a] -> Maybe a mdl xs | null xs = Nothing | otherwise = Just (xs !! p) where p = ((subtract 1) . (`div` 2) . length) xs *Ch1> mdl [1..10] Just 5 *Ch1> mdl [1..20] Just 10 *Ch1> mdl [] Nothing
predict
a) Try to predict the value of each of the following expressions:
[(x,y) | x <- [1..2], y <- [2..5], (x+y) /4]=[x | x <- [1..10], x `mod` 2 =0]=
All the couple (x,y), such that x in [1,2] and y in [2,3,4,5) and that x+y is not 4:
[(x,y) | x <- [1..2], y <- [2..5], (x+y) /= 4] -- [(1,2), (1,4), (1,5), (2,3), (2,4), (2,5)]
All even numbers in [1..10]:
[x | x <- [1..10], x `mod` 2 == 0] = [2,4,6,8,10]
Interpreter:
*Ch1> [(x,y) | x <- [1..2], y <- [2..5], (x+y) /= 4] [(1,2),(1,4),(1,5),(2,3),(2,4),(2,5)] *Ch1> [x | x <- [1..10], x `mod` 2 == 0] [2,4,6,8,10]
b) Define each of the following lists using a list comprehension: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] [2,-3,4,-5,6,-7,8,-9,10,-11]
Answer:
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] = [1..15] = [x | x <- [1..15]] *Ch1> [x | x <- [1..15]] [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
[2,-3,4,-5,6,-7,8,-9,10,-11] = [ if odd x then -1 * x else x | x <- [2..11]] *Ch1> [ if odd x then -1 * x else x | x <- [2..11]] [2,-3,4,-5,6,-7,8,-9,10,-11]
list comprehension
a) Using a list comprehension, define a function neg that counts the number of negative values in a list. For example:
neg [1, -9, 5, 4, -6, 0] = 3b) Using a list comprehension, define the function rep that takes an argument n and returns a list in which 1 occurs one time, 2 occurs 2 two and so one until n occurs n time. For example: =rep 4 => [1,2,2,3,3,3,4,4,4,4]
a)
neg :: [Int] -> Int neg xs = sum [1 | x <- xs, x < 0 ] *Ch1> neg [1, -9, -5, 4, -6, 0] 3
b)
rep :: Int -> [Int] rep n = [ y | x <- [1..n], y <- replicate x x] *Ch1> rep 0 [] *Ch1> rep 1 [1] *Ch1> rep 2 [1,2,2] *Ch1> rep 3 [1,2,2,3,3,3] *Ch1> rep 4 [1,2,2,3,3,3,4,4,4,4]
string2int
Define a function
string2intthat converts a string of digits into the corresponding integer. For example: string2int "3454" = 3454 string2int "76" = 76
string2int :: String -> Int string2int xs = sum [ ((* u) . digitToInt) x | (u, x) <- zip unit (reverse xs)] where unit = iterate (* 10) 1 *Ch1> string2int "123" 123 *Ch1> string2int "3434" 3434 *Ch1> string2int "3454" 3454 *Ch1> string2int "76" 76
Or we could use the standard function read :: Read a => String -> a
Predict
Try to predict the values of the following expressions:
map fst [(1,2), (3,8), (0,6), (3,1)] (foldr f 0 l, foldl f 0 l) where l = [6,9,8,3,10] f x y = (x+y) `div` 2 foldr (++) [] [[1,2,3], [4,5,6], [], [7]]
a)
Recall the definition of:
fst :: (a,b) -> a fst (x,_) = x map :: (a -> b) -> [a] -> [b] map _ [] = [] map f (x:xs) = f x : map f xs -- or using list comprehension: map f xs = [ f x | x <- xs]
We can then conclude:
map fst [(1,2), (3,8), (0,6), (3,1)] = [1,3,0,3]
b) Again recall the definition of foldr:
foldr :: (a -> b -> b) -> b -> [a] -> b foldr _ x [] = x foldr f x (y:ys) = f y $ foldr f x ys
Thus:
foldr f 0 l = foldr f 0 [6,9,8,3,10] = f 6 (foldr f 0 [9,8,3,10]) = f 6 (f 9 (foldr f 0 [8,3,10])) = ... = f 6 (f 9 (f 8 (f 3 (f 10 0)))) = f 6 (f 9 (f 8 (f 3 (10+0 `div` 2)))) = f 6 (f 9 (f 8 (f 3 5))) = f 6 (f 9 (f 8 (3 + 4 `div` 2))) = f 6 (f 9 (f 8 3)) = f 6 (f 9 5) = f 6 7 = 6
Now the right operand, using foldl as operations:
foldl :: (a -> b -> a) -> a -> [b] -> a foldl _ x [] = x foldl f x (y:ys) = foldl f (f x y) ys
Thus (I do not forget that haskell is lazy, just bear with me)
foldl f 0 l = foldl f 0 [6,9,8,3,10] = foldl f (f 0 6) [9,8,3,10] = foldl f (f 1 9) [8,3,10] = foldl f (f 5 8) [3,10] = foldl f (f 6 3) [10] = foldl f (f 5 10) [] = foldl f 7 [] = 7
to conclude:
(foldr f 0 l, foldl f 0 l) where l = [6,9,8,3,10] f x y = (x+y) `div` 2 -- (6,7)
Indeed:
tmp :: (Integer, Integer) tmp = (foldr f 0 l, foldl f 0 l) where l = [6,9,8,3,10] f x y = (x+y) `div` 2 *Ch1> tmp (6,7)
type
What is the type of the following function?
compose f g x = f (g x)
As we can see from the definition of compose:
- f and g takes one parameter each.
 - f takes the output type of g as input.
 
We can sum up the definition of g and f:
g :: a -> b f :: b -> c
Thus:
compose :: (b -> c) -> (a -> b) -> a -> c
Check:
compose :: (b -> c) -> (a -> b) -> a -> c compose f g x = f (g x)
Using compose, we could redefine the string2int function from earlier:
string2int' :: String -> Int string2int' xs = sum [ compose (* u) digitToInt x | (u, x) <- zip unit (reverse xs)] where unit = iterate (* 10) 1
The standard composition function is (.)
*Ch1> :t (.) (.) :: (b -> c) -> (a -> b) -> a -> c
matrix
Given the matrix:
2 3 4 5 6 7 8 9 10 a) Define a function that transposes a square matrix of size 3. If applied to the previous matrix, the result should be:
2 5 8 3 6 9 4 7 10 b) Extends this definition for a matrix of any size
a)
transpose3 :: [[a]] -> [[a]] transpose3 xs = map (\ n -> map (!! n) xs) [0..2] *Ch1> transpose3 [[1,2,3], [4,5,6], [7,8,9]] [[1,4,7],[2,5,8],[3,6,9]]
b)
transpose :: [[a]] -> [[a]] transpose xs = map (\ n -> map (!! n) xs) [0..l] where l = length xs - 1 *Ch1> transpose [[1,2,3], [4,5,6], [7,8,9]] [[1,4,7],[2,5,8],[3,6,9]] *Ch1> transpose [[1,2,3,4], [5,6,7,8], [9,10,11,12], [13,14,15,16]] [[1,5,9,13],[2,6,10,14],[3,7,11,15],[4,8,12,16]]
type
Determine the type definitions (with the context) of the following functions:
cube x = x * x * x maxi x y | x >= y = x | otherwise = y sumAtoB a b = sum [a..b]
We must be able to compute the multiplication on x, so this must be of type Num.
cube :: Num a => a -> a cube x = x * x * x
We must be able to compare the number, so type Ord.
maxi :: (Ord a) => a -> a -> a maxi x y | x >= y = x | otherwise = y
We must be able to compute the sum, so Num type and use a list comprehension, so Enum type.
sumAtoB :: (Num a, Enum a) => a -> a -> a sumAtoB a b = sum [a..b]
