Home > Software engineering >  Hasekll double 2nd element in a list
Hasekll double 2nd element in a list

Time:10-22

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)))
       
  • Related