Dropcaps

One more or less implicit sub-challenge is actually keeping the spaces. We should not trim spaces from both sides of the string, neither dedup spaces between words.

Haskell

If we use words and unwords to extract the words and then join them back into a single string, we end up trimming each word, therefore deduping the spaces. We need some sort of more standard splitting.

Solution 1

import Data.Char (toLower, toUpper)
import Data.List (intercalate)

upcaseFirst :: [Char] -> [Char]
upcaseFirst ""     = ""
upcaseFirst (c:cs) = toUpper c : map toLower cs

split :: Char -> String -> [String]
split c s = case rest of
              []     -> [chunk]
              _:rest -> chunk : split c rest
  where (chunk, rest) = break (== c) s

dropCap :: String -> String
dropCap str = intercalate " " $ go [] (split ' ' str)
  where
    go :: [String] -> [String] -> [String]
    go acc [] = acc
    go acc (s : ss)
      | length s >= 3 = upcaseFirst s : go acc ss
      | otherwise     = s : go acc ss

The upcaseFirst and split functions were created as helpers.

The go inner function properly capitalizes the first char strings of \(\text{length} >= 3\).

At the very end, we apply intercalate " " to the result of go to turn the list of strings back into a single string.

split keeps an empty string in place of each place it could split on space, which later when intercalate comes into play, ends up adding back all the spaces from the original string.

Here’s how split is working:

λ> split ' ' "  abc de   f  "
["","","abc","de","","","f","",""]

Note how each whitespace is turned into a "" empty string in the resulting array. That is what allows intercalate later to reconstruct the string with the original spaces in place.