-5

How can i remove special characters from string and lowercase it and return it as list in Haskell

for example a sample string :

"I'm 25, working in Switzerland;;"

and get output like

['i','m','working','in','switzerland']

2 Answers2

3

Advice

First off, change your question. It currently reads as though you've been assigned homework and you want to take the shortest route to a grade. I would suggest wording it as "How do I approach simple problem solving in Haskell?" Then give your question as an exemplar of a problem that could be solved. The alternative is to take a hit to your reputation, remembering that even if you delete this question the bad reputation will still haunt you.

Problem Solving

First step: define the problem

Two things need to happen to that string.

  1. Convert all uppercase [A-Z] to lowercase [a-z]
  2. Select out any string of [a-zA-Z] into it's own substring, maintaining the order

    This merits the mention of a fundemental rule of any question answering scenario. Read the question, read the question, read the bloody question!

Looks pretty easy, doesn't it? Of course I am being a little disingenuous, because I selected those two things, and in that order, because I know it'll be easier that way. That's plain old knowledge of Haskell.

Divide and Conquer

How do we search for a solution to number 1?

  • Do it by first principles
  • Google or SOF search
  • Hoogle it! I.e. search for a type signature.

Do it by first principles? No, not on a common problem like this. Sure, if you have some weird custom type and data structure, you'd be forced to. Though you would, if you chose your types carefully, have access to abstractions like Semigroup, Monoid, Functor, Applicative, etc., to make that job easier.

Google or SOF search? ¡Sí, Sí, Señor! This is a good bet. Find someone who has already done the problem. Don't be an idiot! Of course look for an easy way first if it looks like an option. In this case, yes, there is an answer, and it's close at hand. SOF: Converting lowercase to uppercase. Not an exact match, but it does not take a lot of imagination to change toUpper into toLower.

# Give a monkey a fish...
import Data.Char (toLower)

uncapitalize = map toLower

Hoogle it? This is a good solution, but you need to have a good grasp of type signatures (essential if you're working with Haskell) to use it effectively. I got the solution real fast by searching at hoogle with the following:

Char -> Char

NOT char -> char. The first is a type signature of a function that takes a concrete type Char and returns a concrete type Char. The second is the type signature of a function that take ANY type and returns that same type. The first is very specific, the second VERY general. Anyway, you've followed the link by now and you see that the function you were looking for was the first result. Amazing!

toLower :: Char -> Char

Along with the module it is imported from. Noice! But still not as helpful as the SOF answer, since that scaffolds everything for a newbie.

We're not done on this one yet. Just because two sources say that a thing is possible, doesn't mean that you can do it. Jump out to ghci to do some testing. Hopefully with stack ghci. Then from the ghci prompt >

toLower 'A'

will give you 'a'. Where 'A' :: Char. Good. Now to get toLower to work on a list. List brings to mind map immediately, but don't take my word for it. From ghci, try :t map and :t toLower to check their types and how you can chuck them together. You'll probably need to import Data.Char with import Data.Char. Now we're ready to do some chucking and shoving1:

map toLower "AnyThing"

and it may or may not fail depending on if you have :set -XOverloadedStrings in ghci. To be sure, be explicit:

map toLower ("I'm 25, working in Switzerland;;" :: [Char])

and out pops "i'm 25, working in switzerland;;". We're halfway done. By the way, ghci is a common way of working through problems in haskell. Shoving things together like a monkey is how we are wired. Embrace it. Indeed, why think when you can shove away in a consequence free environment? It's a no-brainer.

How do we search for a solution to number 2? This is a tougher problem, but using the same search options we used above.

Do it by first principles? Yes, probably. Though lets search Google and SOF first.

Luckily, it's a problem others have considered before. We get a general solution for free.

wordsWhen     :: (Char -> Bool) -> String -> [String]
wordsWhen p s =  case dropWhile p s of
                   "" -> []
                   s' -> w : wordsWhen p s''
                         where (w, s'') = break p s'

This is a general solution to our problem. It takes a predicate (hence the p) function (Char -> Bool) and drops anything that matches it, and saves the rest. break works by breaking any chunk of Chars that do not match the predicate into w of the tuple (w, s'').

Note on convention: the apostrophe superscript in s' refers to s' being somehow derivative of, or coming from s.

The function wordsWhen calls itself recursively on whatever remains of the string i.e. s'', until it is empty (the first case match).

How do we test this in ghci? I'm glad you asked. To enter a multi-line definition directly into ghci use this bracketing, :{ begins the code block, and :} ends it. Or use :set +m. Both of which are outlined here.

Since the predicate chooses which characters to drop, the logical choice is for it to be (not . isLower). You should have encountered isLower when rooting around in Date.Char. The not is logical negation, and the . is function composition.

Therefore:

wordsWhen (not . isLower) "i'm 25, working in switzerland;;"

solves the second part. Resolving these two into a solution is a job for any monkey who can shove things together using ghci.


[1]: Absolutely no one's formal definition of this activity.

Paul Parker
  • 1,163
  • 12
  • 23
2

I will not answer your question entirely, but I will give you some pointers using hoogle:

  • How will we check for special characters? Maybe there's some function of type Char -> Bool that can help. Possibly isAlphaNum?
  • How will we convert to lowercase? Maybe there's a function of type Char -> Char that can help.
  • How will we apply a function on just Chars to an entire String? Maybe there's a function of type (Char -> Char) -> String -> String. Maybe there's a more general function that can help us?
  • How will we split a string at special characters? This is a tough one, so I'll give you the function break :: (a -> Bool) -> [a] -> ([a], [a]) for free.

Now, given these functions, you can build the complete function you're looking for, by using recursion. Good luck!

AJF
  • 11,767
  • 2
  • 37
  • 64