Using library functions, define a function
halve :: [a] -> ([a],[a])
that splits an even-lengthed list into two halves. For example:> halve [1,2,3,4,5,6] 1,2,3],[4,5,6]) ([
halve :: [a] -> ([a],[a])
= splitAt (((length xs) + 1) `div` 2) xs halve xs
Define a function
third :: [a] -> a
that returns the third element in a list that contains at least this many elements using:
- head and tail;
- list indexing
!!
;- pattern matching.
thirdHeadAndTail :: [a] -> a
= head . tail . tail
thirdHeadAndTail
thirdIndex :: [a] -> a
= xs !! 2
thirdIndex xs
thirdPatternMatching :: [a] -> a
:_:x:_) = x thirdPatternMatching (_
Consider a function
safetail :: [a] -> [a]
that behaves in the same way as tail except that it maps the empty list to itself rather than producing an error. Usingtail
and the functionnull :: [a] -> Bool
that decides if a list is empty or not, definesafetail
using:
- a conditional expression;
- guarded equations;
- pattern matching.
safetailConditional :: [a] -> [a]
= if null xs
safetailConditional xs then []
else tail xs
safetailGuarded :: [a] -> [a]
| null xs = []
safetailGuarded xs | otherwise = tail xs
safetailPatternMatch :: [a] -> [a]
= []
safetailPatternMatch [] :xs) = xs safetailPatternMatch (_
In a similar way to
&&
in section 4.4, show how the disjunction operator||
can be defined in four different ways using pattern matching.
or1 :: Bool -> Bool -> Bool
True `or1` True = True
True `or1` False = True
False `or1` True = True
False `or1` False = True
or2 :: Bool -> Bool -> Bool
False `or2` False = False
`or2` _ = True
_
or3 :: Bool -> Bool -> Bool
False `or3` b = b
True `or3` _ = True
or4 :: Bool -> Bool -> Bool
`or4` b | a == b = b
a | otherwise = True
Without using any other library functions or operators, show how the meaning of the following pattern matching definition for logical conjunction
&&
can be formalized using conditional expressions:True && True = True && _ = False _
Hint: use two nested conditional expressions
formalConjunction :: Bool -> Bool -> Bool
=
formalConjunction a b if a then
if b then
True
else False
else False
Do the same for the following alternative definition, and note the difference in the number of conditional expressions that are required:
True && b = b False && _ = False
formalConjunction :: Bool -> Bool -> Bool
=
formalConjunction a b if a then
belse
False
Show how the meaning of the following curried function definition can be formalized in terms of lambda expressions:
mult :: Int -> Int -> Int -> Int = x*y*z mult x y z
mult :: Int -> Int -> Int -> Int
= \x -> (\y -> (\z -> x * y * z)) mult
The Luhn algorithm is used to check bank card numbers for simple errors such as mistyping a digit, and proceeds as follows:
- consider each digit as a separate number;
- moving left, double every other number from the second last;
- subtract 9 from each number that is now greater than 9;
- add all the resulting numbers together;
- if the total is divisible by 10, the card number is valid.
Define a function
luhnDouble :: Int -> Int
that doubles a digit and subtracts 9 if the result is greater than 9. For example:> luhnDouble 3 6 > luhnDouble 6 3
Using
luhnDouble
and the integer remainder function mod, define a functionluhn :: Int -> Int -> Int -> Int -> Bool
that decides if a four-digit bank card number is valid. For example:> luhn 1 7 8 4 True > luhn 4783 False
luhnDouble :: Int -> Int
| n <= 5 = 2 * n
luhnDouble n | otherwise = 2 * n - 9
luhn :: Int -> Int -> Int -> Int -> Bool
=
luhn a b c d + b + luhnDouble c + d)
(luhnDouble a `mod` 10 == 0