How does the recursive version of the factorial function behave if applied to a negative argument, like β ββ 1? Modify the definition to prohibit negative arguments by adding a guard to the recursive case.
facRecursive :: Int -> Int
facRecursive n| n < 0 = 0
| n == 0 = 1
| otherwise = n * facRecursive (n - 1)
Define a recursive function
sumdown :: Int -> Int
that returns the sum of the non-negative integers from a given value down to zero. For example,sumdown 3
should return the result 3β +β 2β +β 1β +β 0β=β6.
sumdown :: Int -> Int
0 = 0
sumdown = n + sumdown (n - 1) sumdown n
Define the exponentiation operator
^
for non-negative integers using the same pattern of recursion as the multiplication operator*
and show how the expression2 ^ 3
is evaluated using your definition.
(^) :: Int -> Int -> Int
0 ^ _ = 0
^ 0 = 1
_ ^ m = n * (n ^ (m - 1)) n
Define a recursive function
euclid :: Int -> Int -> Int
that implements Euclidβs algorithm for calculating the greatest common divisor of two non-negative integers: if the two numbers are equal, this number is the result; otherwise, the smaller number is subtracted from the larger, and the same process is then repeated. For example:> euclid 6 27 3
euclid :: Int -> Int -> Int
euclid n m | n == m = n
| n > m = euclid m (n - m)
| n < m = euclid n (m - n)
Using the recursive definitions given in this chapter, show how
length [1,2,3]
,drop 3 [1,2,3,4,5]
, andinit [1,2,3]
are evaluated.
For length
:
length [1,2,3]
={ applying length }
1 + length [2,3]
={ applying length }
1 + (1 + length [3])
={ applying length }
1 + (1 + (1 + length []))
={ applying length }
1 + (1 + (1 + (0)))
={ applying + }
3
For drop
:
drop 3 [1,2,3,4,5]
={ applying drop }
drop 2 [2,3,4,5]
={ applying drop }
drop 1 [3,4,5]
={ applying drop }
drop 0 [3,4,5]
=[3,4,5]
For init
(the definition is provided below for reference):
init :: [a] -> [a]
init [_] = []
init (x:xs) = x : init xs
init [1,2,3]
={ applying init }
1 : init [2,3]
={ applying init }
1 : 2 : init [3]
={ applying init }
1 : 2 : []
={ list notation }
1,2] [
Without looking at the definitions from the standard prelude, define the following library functions on lists using recursion:
- Decide if all logical values in a list are true:
and :: [Bool] -> Bool
- Concatenate a list of lists:
concat :: [[a]] -> [a]
- Produce a list with n identical elements:
replicate :: Int -> a -> [a]
- Select the nth element of a list:
(!!) :: [a] -> Int -> a
- Decide if a value is an element of a list:
elem :: Eq a => a -> [a] -> Bool
Note: most of these functions are defined in the prelude using other library functions rather than using explicit recursion, and are generic functions rather than being specific to the type of lists.
-- Part a
and :: [Bool] -> Bool
and [] = True
and (False:_) = False
and (_:xs) = and xs
-- Part b
concat :: [[a]] -> [a]
concat [] = []
concat (xs:xss) = xs ++ concat xss
-- Part c
replicate :: Int -> a -> [a]
replicate 0 _ = []
replicate n a = [a] ++ replicate (n - 1) a
-- Part d
-- For simplicity, assume that the index is valid
-- and that the array is non-empty
(!!) :: [a] -> Int -> a
:_) !! 0 = x
(x:xs) !! n = xs !! (n - 1)
(_
-- Part e
elem :: Eq a => a -> [a] -> Bool
elem _ [] = False
-- Note: ys can be [] which is why (y:ys) matches singletons
elem x (y:ys)
| x == y = True
| x /= y = elem x ys
Define a recursive function
merge :: Ord a => [a] -> [a] -> [a]
that merges two sorted lists to give a single sorted list.For example:
> merge [2,5,6] [1,3,4] 1,2,3,4,5,6] [
Note: your definition should not use other functions on sorted lists such as
insert
orisort
, but should be defined using explicit recursion.
merge :: Ord a => [a] -> [a] -> [a]
= y'
merge [] y' = x'
merge x' [] @(x:xs) y'@(y:ys)
merge x'| (x <= y) = x : merge xs y'
| otherwise = y : merge x' ys
Using
merge
, define a functionmsort :: Ord a => [a] -> [a]
that implements merge sort, in which the empty list and singleton lists are already sorted, and any other list is sorted by merging together the two lists that result from sorting the two halves of the list separately. Hint: first define a functionhalve :: [a] -> ([a],[a])
that splits a list into two halves whose lengths differ by at most one.
halve :: [a] -> ([a],[a])
= splitAt (div (length xs) 2) xs
halve xs
msort :: Ord a => [a] -> [a]
= []
msort [] = [x]
msort [x] = merge (msort a) (msort b)
msort xs where a = fst $ halve xs
= snd $ halve xs b
Using the five-step process, construct the library function that:
- Calculates the sum of a list of numbers;
- takes a given number of elements from the start of a list;
- Selects the last element of a non-empty list.
-- Part a
sumOfList :: Num a => [a] -> a
= 0
sumOfList [] :xs) = x + (sumOfList xs)
sumOfList (x
-- Part b
takeFromList :: Int -> [a] -> [a]
= []
takeFromList _ [] 0 _ = []
takeFromList :xs) = x : takeFromList (n - 1) xs
takeFromList n (x
-- Part c
lastElem :: [a] -> a
= x
lastElem [x] :xs) = lastElem xs
lastElem (_= error "List is empty!" lastElem []