6
votes

I have to write a function which uppercase the FIRST letter of a string and also LOWERCASE the rest of the string (This string contains random uppercased or lowercased letters).

So far, I have managed to do this:

capitalised :: String->String
capitalised [] = []
capitalised x
            | length x == 1 = map toUpper x
            | otherwise = capitalised (init x): map toLower (last x)

and all other sort of weird functions, and I still could not figure it out.

Please help! Tx in advance!

Forgot to mention, the problem states that I need to write a recursive solution!

5
Please, don't post homework problems here...agarie

5 Answers

24
votes

Remember that a String is just a type synonym for [Char]? Here we utilize that:

import qualified Data.Char as Char

capitalized :: String -> String
capitalized (head:tail) = Char.toUpper head : map Char.toLower tail
capitalized [] = []

Here is a recursive version:

capitalized :: String -> String
capitalized [] = []
capitalized (head:tail) = Char.toUpper head : lowered tail
  where
    lowered [] = []
    lowered (head:tail) = Char.toLower head : lowered tail
9
votes

Warning: This solution is likely overkill, and not for newbies, but here's how to do it using traversals from the lens package.

import Control.Lens
import Data.Char

capitalize :: *really scary type would go here*
capitalize = over _head toUpper . over (_tail.each) toLower

Where _head and _tail are from Control.Lens.Cons, each is from Control.Lens.Each, and over is from Control.Lens.Setter.

The nice thing about this definition is that it should work with Seq, Vector, Text and other datatypes besides String, because they all are instances of Cons and Each. For example:

import qualified Data.Text as T
import qualified Data.Sequence as S

over _head toUpper . over (_tail.each) toLower $ "aA"
-- "Aa"
over _head toUpper . over (_tail.each) toLower $ T.pack "aA"
-- "Aa"
over _head toUpper . over (_tail.each) toLower $ S.fromList "aA"
-- "Aa"

Edit: Here's one more way to do it, just for the hell of it.

import Data.Char 
import Control.Lens 
import Control.Arrow (***)

over _Cons (toUpper *** over each toLower) "aA"
0
votes

You have an error on line:

| otherwise = capitalised (init x): map toLower (last x)

just use head and tail, not init and last:

capitalised [] = []
capitalised x = 
        | length x == 1 = map toUpper x
        | otherwise     = head (capitalised [head x]) : map toLower (tail x)

This solution is not optimal. Nikita Volkov's version is prettier. Or we could rewrite it to

capitalised [] = []
capitalised x = toUpper (head x) : map toLower (tail x)
0
votes

Couple more ways to do this, with the help of various libraries:

Prelude> :m +Data.Char Data.List
> let ucfirst x = (toUpper $ head x) : (toLower <$> tail x)

Prelude> :m +Data.Char Data.List Control.Arrow
> let ucfirst = (head >>> toUpper) &&& (tail >>> (toLower <$>)) >>> uncurry (:)

Prelude> :m +Data.Char Data.List Control.Applicative
> let ucfirst = liftA2 (:) (toUpper . head) ((toLower <$>) . tail)

They all do the same thing:

> ucfirst "fOO"
"Foo"
0
votes

Came here because I had to answer the same question, and came up with this solution

capitalised [] = []
capitalised xs  | length xs == 1 = capitalised (init xs) ++ [toUpper c | c<-xs]
                | otherwise = capitalised (init xs) ++ [toLower c | c<-xs, c == last xs]

Thought it was the most recursive answer accessible for beginners :)