Your foldr
solution doesn't work because it's using the empty list you're passing in the final step. You can use foldr1
instead, it uses the final element of the list in place of being passed an accumulator value.
Looking to the fold
s to implement unwords
isn't a bad idea, but there are other high-level functions that you can use to write a more terse or readable version. Let's start from a verbal description of what unwords
is doing.
Insert a space character between every String
in a list, then join the resulting String
s together.
The latter half of that description is easy, we know that String
is really [Char]
, and we can easily flatten doubly-nested lists with concat
. The former portion we could implement on our own, or search Hoogle for to see if anything already exists in the Prelude
or other modules that could help us out. In this case, we're looking for a function with the type a -> [a] -> [a]
, that is, we want to pass it a value and a list and have it return a list with that value inserted between each pair of elements. As luck would have it, there's a function in Data.List
that does exactly what we're looking for called intersperse
that comes up as the first result if we perform that search.
Using these two functions, we can write a very short version of unwords
that reads almost like prose.
import Data.List (intersperse)
import Prelude hiding (unwords)
unwords :: [String] -> String
unwords = concat . intersperse " "
Besides the aesthetic appeal of this solution, to me this illustrates the power of thinking about what you want to do in Haskell, instead of thinking about how it's going to be done.