Search code examples
haskellfunctional-programmingpurely-functional

How do I extend this mergeWords function to any number of strings?


Following is the mergeWords function.

mergeWords [] [] = []
mergeWords [] (y:ys) = y:'\n':(mergeWords [] ys)
mergeWords (x:xs) [] = x:'\n':(mergeWords xs [])
mergeWords (x:xs) (y:ys) = x:y:'\n':(mergeWords xs ys)

If applied on mergeWords "hello" "world" it gives

"hw\neo\nlr\nll\nod\n"

I can't figure out how to extend this to list of strings. Like applying it to 3 strings should first take first character of each of the strings and then put a '\n' and then the second character and so on.


Solution

  • Sounds reasonably easy if you do it in steps:

    cutWords :: [String] -> [[String]]    -- ["ab", "cd", "e"] -> [["a", "c", "e"], ["b", "d"]]
    concatWord :: [String] -> String       -- ["a", "c", "e"] -> "ace\n"
    concatWords :: [String] -> String    -- use mergeWord on all of them
    

    The most interesting part is of course the cutWords part. What you want there is a zip-like behaviour, and for that it'll help if we "safe" tail and head:

    head' (x:xs) = [x]
    head' "" = ""
    
    tail' (x:xs) = xs
    tail' "" = ""
    

    Now we can implement our cutWords, making sure we stop in time:

    cutWords xs = heads : rest
      where
        heads = map head' xs
        tails = map tail' xs
        rest = if any (/= "") tails then cutWords tails
                                    else []
    

    Then the remaining part is trivial:

    concatWord word = concat word ++ "\n"
    concatWords words = concatMap concatWord word