Scott Myers
Scott Myers

Reputation: 202

Concatenate List of Strings, adding a separator in between using foldl Haskell

I have a function that is meant to combine strings in a list, adding a separator in between each and outputting a single string using foldl. Here is what I have and some expected behavior of the function -- It isn't working and I'm unsure why.

-- | `sepConcat sep [s1,...,sn]` returns `s1 ++ sep ++ s2 ++ ... ++ sep ++ sn`
--
-- >>> sepConcat "---" []
-- ""
--
-- >>> sepConcat ", " ["foo", "bar", "baz"]
-- "foo, bar, baz"
--
-- >>> sepConcat "#" ["a","b","c","d","e"]
-- "a#b#c#d#e"

sepConcat :: String -> [String] -> String
sepConcat sep []     = ""
sepConcat sep (x:xs) = foldLeft f base l
  where
    f a x            = a ++ sep ++ x
    base             = ""
    l                = xs

Upvotes: 2

Views: 1297

Answers (2)

developer_hatch
developer_hatch

Reputation: 16224

The huge problem is your pattern matching:

sepConcat sep []     = ""
sepConcat sep (x:xs) = foldLeft f base l

You don't need to divide the patterns again in [] and (x:xs) because foldl and foldr take care of both cases. This is how foldl can be defined to list with recursion:

foldLeft :: (b -> a -> b) -> b -> [a] -> b
foldLeft f base []     = base
foldLeft f base (x:xs) = f (foldLeft f base xs) x

you just need to apply correctly both cases:

sepConcat :: String -> [String] -> String
sepConcat sep xs = foldLeft (\rs s ->
 if null rs 
 then s ++ rs
 else s ++ sep ++ rs) "" xs

Here the case of the empty list is "" and the function is for the recursive case of the list

with your example:

sepConcat ", " ["foo", "bar", "baz"]
=> "foo, bar, baz"

Upvotes: 0

Brady Dean
Brady Dean

Reputation: 3573

I think you can solve this simply by checking if the first argument is the empty string and handling it accordingly

sepConcat sep = foldl (\x y -> if x == "" then y else x ++ sep ++ y) ""
-- or
sepConcat sep = foldl combine ""
  where combine "" x = x
        combine x y = x ++ sep ++ y

Upvotes: 0

Related Questions