Capitalizing first letter of words while removing spaces (Haskell)

こ雲淡風輕ζ 提交于 2020-01-24 10:47:05

问题


I'm just starting out in Haskell and this is like the third thing I'm writing, so, naturally, I'm finding myself a little stumped.

I'm trying to write a bit of code that will take a string, delete the spaces, and capitalize each letter of that string.

For example, if I input "this is a test", I would like to get back something like: "thisIsATest"

import qualified Data.Char as Char

toCaps :: String -> String
toCaps [] = []
toCaps xs = filter(/=' ') xs
toCaps (_:xs) =  map Char.toUpper xs 

I think the method I'm using is wrong. With my code in this order, I am able to remove all the spaces using the filter function, but nothing becomes capitalize.

When I move the filter bit to the very end of the code, I am able to use the map Char.toUpper bit. When I map that function Char.toUpper, it just capitalizes everything "HISISATEST", for example. I was trying to make use of an if function to say something similar to

if ' ' then map Char.toUpper xs else Char.toLower xs, but that didn't work out for me. I haven't utilized if in Haskell yet, and I don't think I'm doing it correctly. I also know using "xs" is wrong, but I'm not sure how to fix it. Can anyone offer any pointers on this particular problem?


回答1:


I think it might be better if you split the problem into smaller subproblems. First we can make a function that, for a given word will capitalize the first character. For camel case, we thus can implement this as:

import Data.Char(toUpper)

capWord :: String -> String
capWord "" = ""
capWord (c:cs) = toUpper c : cs

We can then use words to obtain the list of words:

toCaps :: String -> String
toCaps = go . words
    where go [] = ""
          go (w:ws) = concat (w : map capWord ws)

For example:

Prelude Data.Char> toCaps "this is a test"
"thisIsATest"

For Pascal case, we can make use of concatMap instead:

toCaps :: String -> String
toCaps = concatMap capWord . words



回答2:


Inspired by this answer from Will Ness, here's a way to do it that avoids unnecessary Booleans and comparisons:

import qualified Data.Char as Char

toCaps :: String -> String
toCaps = flip (foldr go (const [])) id
  where go ' ' acc _ =     acc Char.toUpper
        go x   acc f = f x:acc id

Or more understandably, but perhaps slightly less efficient:

import qualified Data.Char as Char

toCaps :: String -> String
toCaps = go id
  where go _ []       =     []
        go _ (' ':xs) =     go Char.toUpper xs
        go f (x  :xs) = f x:go id           xs



回答3:


There are a number of ways of doing it, but if I were trying to keep it as close to how you've set up your example, I might do something like:

import Data.Char (toUpper)

toCaps :: String -> String
toCaps []         = []                    -- base case
toCaps (' ':c:cs) = toUpper c : toCaps cs -- throws out the space and capitalizes next letter
toCaps (c:cs)     = c : toCaps cs         -- anything else is left as is

This is just using basic recursion, dealing with a character (element of the list) at a time, but if you wanted to use higher-order functions such as map or filter that work on the entire list, then you would probably want to compose them (the way that Willem suggested is one way) and in that case you could probably do without using recursion at all.

It should be noted that this solution is brittle in the sense that it assumes the input string does not contain leading, trailing, or multiple consecutive spaces.




回答4:


Inspired by Joseph Sible 's answer, a coroutines solution:

import Data.Char

toCamelCase  :: String -> String
toCamelCase  []         =  []
toCamelCase  (' ': xs)  =  toPascalCase xs
toCamelCase  (x  : xs)  =          x : toCamelCase xs

toPascalCase :: String -> String
toPascalCase []         =  []
toPascalCase (' ': xs)  =  toPascalCase xs
toPascalCase (x  : xs)  =  toUpper x : toCamelCase xs

Be careful to not start the input string with a space, or you'll get the first word capitalized as well.



来源:https://stackoverflow.com/questions/58087750/capitalizing-first-letter-of-words-while-removing-spaces-haskell

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!