159

Is there a function to concatenate elements of a list with a separator? For example:

> foobar " " ["is","there","such","a","function","?"]
["is there such a function ?"]

Thanks for any reply!

4
  • 17
    I know lmgtfy answers are bad, but it's worth noting that a search for "String -> [String] -> String" on hoogle gets just what you want. haskell.org/hoogle Commented Feb 10, 2012 at 0:24
  • 4
    for joining with spaces you also have unwords Commented Feb 10, 2012 at 13:58
  • 1
    @sigfpe Side comment: You would have to look for [String] -> String -> String in case that the other way returns no answer, right? Commented Mar 8, 2014 at 21:41
  • 1
    @LayGonzález The search is up to permutations. For instance searching for [a] -> (a -> b) -> [b] returns map as its first result. Commented Jun 18, 2016 at 23:15

5 Answers 5

273

Yes, there is:

Prelude> import Data.List
Prelude Data.List> intercalate " " ["is","there","such","a","function","?"]
"is there such a function ?"

intersperse is a bit more general:

Prelude> import Data.List
Prelude Data.List> concat (intersperse " " ["is","there","such","a","function","?"])
"is there such a function ?"

Also, for the specific case where you want to join with a space character, there is unwords:

Prelude> unwords ["is","there","such","a","function","?"]
"is there such a function ?"

unlines works similarly, only that the strings are imploded using the newline character and that a newline character is also added to the end. (This makes it useful for serializing text files, which must per POSIX standard end with a trailing newline)

Sign up to request clarification or add additional context in comments.

6 Comments

Can any of it deal with possible empty strings?
@CMCDragonkai Not sure what exactly you're referring to, but yes, these functions all allow arbitrary strings as both the separator and the elements. For example, intercalate "," ["some", "", "string"] = "some,,string" and intercalate "" ["foo", "bar"] = "foobar"
unlines adds a newline to each line, that is unlines ["A", "B"] = "A\nB\n", so it is not the same as intercalate.
@KathyVanStone Interesting, I guess I never tried and only assumed it works analogously to unwords.
It's nice that there are some normal string and list manipulation functions in the standard library, and it's nice that you're posting an example here, because it's pretty hard to find any documentation for this kind of everyday programming in Haskell.
|
7

It's not hard to write one-liner using foldr

join sep xs = foldr (\a b-> a ++ if b=="" then b else sep ++ b) "" xs
join " " ["is","there","such","a","function","?"]

2 Comments

It would be beneficial to add a description to this; someone flagged it as low quality.
This concept of folding is sorta like reduce (if you know what reduce is). Foldr (fold right) applies a function to each element in a list and adds the result to an accumulator. It then returns the accumulated value. Here we are declaring a function join which accepts a separator and a string list. It then applies fold on the list using an anonymous lambda function. In (\a b-> a ++ if b=="" then b else sep ++ b) a is the accumulator, b is the next item on the list. The fold starts with ""
4

Some other ideas of implementations of intersperse and intercalate, if someone is interested:

myIntersperse :: a -> [a] -> [a]
myIntersperse _ [] = []
myIntersperse e xs = init $ xs >>= (:[e])

myIntercalate :: [a] -> [[a]] -> [a]
myIntercalate e xs = concat $ myIntersperse e xs

xs >>= f is equivalent to concat (map f xs).

Comments

3
joinBy sep cont = drop (length sep) $ concat $ map (\w -> sep ++ w) cont

Comments

3

If you wanted to write your own versions of intercalate and intersperse:

intercalate :: [a] -> [[a]] -> [a]
intercalate s [] = []
intercalate s [x] = x
intercalate s (x:xs) = x ++ s ++ (intercalate s xs)

intersperse :: a -> [a] -> [a]
intersperse s [] = []
intersperse s [x] = [x]
intersperse s (x:xs) = x : s : (intersperse s xs)

4 Comments

Why limit yourself to strings? Also, your parens around the function application are redundant.
True, intersperse needn't be Strings, but intercalate would need to at least be Show, and if you did use Show, you'd need some way to deal with them using Strings anyway. I'm still getting used to how Haskell deals with mixed infix and prefix functions/operators, and I prefer bracketing when mixing in case I end up wanting to use $
intercalate :: [a] -> [[a]] -> [a] - why Show? As for syntax, Haskell doesn't have any prefix operators (except for -, which is an abomination), and function application binds tighter than any infix operator: x:s:intersperse s xs is fine (but it reads much better if you put the spaces in: x : s : intersperse s xs (I don't really understand why people like to leave out the spaces around :)).
Right. I keep forgetting that working with strings is just working with lists. Show was because I was assuming you'd want the result to be a String. By "infix and prefix functions/operators" I meant "prefix functions and infix operators", but that was unclear. Unary - is death. As for the :s and other infix operators, whether I use spaces depends highly on context, but I'm always locally consistent. eg, (:) in a pattern match never has spaces, but elsewhere it depends on whether it's bracketed and on my mood.

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.