Anil
Anil

Reputation: 175

What is wrong with this Haskell list code?

Here is an example of what I wanted to do.

let b = ["this","is","a","test!"]

"xx" ++ (b!!3)

This will give me "xxtest!"

Basically if the list contains any string with an exclamation mark then "xx" will be added to this specific string. My questions is how to implement this into a correct function.

Currently I got this

replaceElement [] = []
replaceElement (x:xs) =
      if '!' `elem` x
      then ["xx"] ++ x : replaceElement xs
      else x: replaceElement xs

But this function will just add "xx" into list as an element, it won't be added to the specific string in the list. How can I use "xx" ++ (b!!x) where x is the position of the string with an exclamation mark.

Upvotes: 0

Views: 77

Answers (3)

Redu
Redu

Reputation: 26161

You may also use map with a helper function like;

addxx :: [String] -> [String]
addxx = map checkBang
        where checkBang s | last s == '!' = "xx" ++ s
                          | otherwise     = s

Upvotes: 0

leftaroundabout
leftaroundabout

Reputation: 120711

The crucial thing is how ["xx"] ++ x : replaceElement xs is parsed. This is determined by the fixities of the operators:

GHCi, version 7.10.2: http://www.haskell.org/ghc/  :? for help
Prelude> :info :
-- ...
infixr 5 :
Prelude> :i ++
(++) :: [a] -> [a] -> [a]   -- Defined in ‘GHC.Base’
infixr 5 ++

So, both : and ++ are right-associative operators, with the same precedence. Right-associative means, a : b : c is parsed as a : (b : c), instead of (a : b) : c (as would be the case for left-associative infixl). Due to the equal precedence, this still holds if you mix : and ++, i.s.

["xx"] ++ x : replaceElement xs  ≡  ["xx"] ++ (x : replaceElement xs)

IOW, you're just prepending ["xx"] to the whole result, but the individual elements never get in contact with "xx". To achieve that, you need to group "xx" with x. The extra brackets are unnecessary then (in fact these could have tipped you off: wrapping "xs" in an extra layer means you're not working of the string-level anymore as intended, but on the list-of-string level).


A better alternative would of course be to not do any manual recursion: you're simply applying the same operation to all elements of a list; that's what map is there for:

replaceElement = map $ \x -> if '!'`elem`x
                              then "xx"++x
                              else x

Upvotes: 3

bereal
bereal

Reputation: 34252

The expression

["xx"] ++ x : replaceElement xs

is actually parsed as

["xx"] ++ (x : replaceElement xs)

which does just what you described: inserts "xx" into the resulting list. What you want to do instead, is:

("xx" ++ x) : replaceElement xs

Upvotes: 4

Related Questions