1

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.
8
  • 1
    Please indicate how the code deviates from your expectation. Is there a compiler error? What is that error? Does the program give incorrect output? What is an example of an input and incorrect output? Commented Aug 27, 2017 at 15:11
  • Start simpler: can you write a function f from to x that evaluates to to if x is equal to from and x unchanged otherwise? Commented Aug 27, 2017 at 15:11
  • On compilation, I am getting a parse error and the compiler is suggesting me to add 'let' in the 'do block' Commented Aug 27, 2017 at 15:15
  • @RNee please edit your question to include the exact text of the parse error. Commented Aug 27, 2017 at 15:17
  • 1
    A good first step into Haskell is forgetting that you ever heard of assignments. Commented Aug 28, 2017 at 10:44

1 Answer 1

5

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)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.