I do have the following code:
data List = Empty | Cons Integer List deriving Show
list = Cons 1 (Cons 7 (Cons 9 (Cons 3 Empty)))
Now I am writing a function that doubles every 2nd element in a list:
double2nd :: List -> List
double2nd Empty = Empty --If the list is empty, nothing to do
double2nd (Cons x y z) = ???
I have the following test case lined up:
testDouble = putStrLn ("expected: Cons 1 (Cons 14 (Cons 9 (Cons 6 Empty)))\ncomputed: " show (double2nd list))
I tried looking up lists on various web pages but came to no conclusion.
Any help or any pages where I can learn that would be appreciated.
CodePudding user response:
Stuf which is normally done with loops in other languages are done with recursion in haskell:
double2nd :: List -> List
double2nd Empty = Empty -- check if list is completexly empty
double2nd (Cons i Empty) = Cons i Empty -- check if list is only containing one element
double2nd (Cons i (Cons i2 l))= Cons i (Cons (i2 * 2) (double2nd l)) -- recusion step
CodePudding user response:
Cons takes two arguments, a Integer and a List, therefore you can't pattern match Cons x y z
.
double2nd :: List -> List
double2nd Empty = Empty --If the list is empty, nothing to do
double2nd (Cons x (Cons y (Cons z Empty))) = ... -- this will match a 3 element list
Notice above that every second argument to Cons is a List. But this pattern is not quite right, it only works for lists with exactly 3 elements. This happens with we try to match it agains list:
λ> Cons x (Cons y (Cons z Empty)) = list
λ> [x,y,z]
[*** Exception: <interactive>:151:1-39: Non-exhaustive patterns in Cons x (Cons y (Cons z Empty))
-- making it work with exactly 3 elements:
λ> Cons x (Cons y (Cons z Empty)) = Cons 1 (Cons 7 (Cons 9 Empty))
λ> [x,y,z]
[1,7,9]
-- making it work with larger lists:
λ> Cons x (Cons y (Cons z _)) = Cons 1 (Cons 7 (Cons 9 Empty))
λ> [x,y,z]
[1,7,9]
The last pattern _
ignores the value for the second argument to the last Cons, it has the drawback of losing this value. I suspect to solve your problem you'd need to run the function over all elements. For that we can bind to matched pattern using @
:
λ> Cons x (Cons y (Cons z tl@_)) = list
λ> [x,y,z]
[1,7,9]
λ> tl
Cons 3 Empty
Fixing your function:
double2nd :: List -> List
double2nd Empty = Empty
double2nd (Cons x (Cons y (Cons z tl@_))) = Cons x (Cons (2*y) (Cons z tl))
-- ^ will match list with 3 or more elements
λ> double2nd list
Cons 1 (Cons 14 (Cons 9 (Cons 3 Empty)))