RNee
RNee

Reputation: 47

Haskell Replace a value in a list with another value

I am pretty new to Haskell. I am trying to write a program that takes two values and a list and replaces every instance of the first value in the list with the second. E.g. repOcc 'n' 'i' "pink" would return "piik".

The following is my code:

repOcc :: t -> t -> [t] -> [t]
repOcc x y (z:zs) = if z == x
                      then z = y
                      subst x y zs
                      else subst x y zs

The error I am receiving at compile time is:

rev.hs:3 :32: error: 
   parse error on input '='
   Perhaps you need a 'let' in a 'do' block?
   e.g. 'let x = 5' instead of 'x = 5'
Failed, modules loaded: none.

Upvotes: 1

Views: 3149

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477641

Your program looks rather "imperative" whereas Haskell aims to be more "declarative". So you can not set a variable z in a list: once a list is constructed, you can not alter it anymore. So you have to construct a new list where elements that are equal to x are set to y.

Next you make use of the (==) function. That function is defined in the Eq typeclass, so you need to add Eq t as a type constraint to the signature.

So now we can start to construct such function. Usually when working with a list, we make use of recursion. The base case of the recursion is usually the empty list. In case we encounter the empty list, we should return an empty list, regardless what x and y are. So we use underscores as "don't care" patterns, and use [] as the list pattern, and write:

repOcc _ _ [] = []

The recursive case is when the list contains a head h and a tail t in a (h:t) pattern. In that case we check whether h is equal to x. In case it is, we construct a list with y as head, otherwise h is still the head.

repOcc x y (h:t) | x == h = y : tl
                 | otherwise = h : tl

Now the question remains what the tail of the result list tl should be. Here we use recursion, so we call repOcc with x y t:

    where tl = repOcc x y t

Or putting it together:

repOcc :: Eq t => t -> t -> [t] -> [t]
repOcc _ _ [] = []
repOcc x y (h:t) | x == h = y : tl
                 | otherwise = h : tl
    where tl = repOcc x y t

We can write such recursive functions, but the above is actually a special case of a map function: we map every character in such way that we check whether it is equal to x and if it is, we return y, otherwise we return h. So we can rewrite the above as:

repOcc :: Eq t => t -> t -> [t] -> [t]
repOcc x y ls = map (\h -> if h == x then y else h) ls

We can further improve the code by making use of eta-reduction:

repOcc :: Eq t => t -> t -> [t] -> [t]
repOcc x y = map (\h -> if h == x then y else h)

Upvotes: 5

Related Questions