2

Im trying to write a function that takes in a string and then returns the string as a list of string-words (like the words built-in function) and so far i've written

ord :: String -> [String]
ord [] = []
ord xs = let
    ys = groupBy (\x y -> y /= ' ') xs
    in filter (not . null) ys

I thougth this would get rid of the empty strings from the list but i only get this output

input:

ord  “aa b       c   -    dd” 

output:

["aa"," b"," "," "," "," "," "," "," c"," "," "," -"," "," "," "," dd"]

when this is the output i want:

[“aa”, ”b”, ”c”, ”-“, ”dd”]

I get the same result if i try and write

ord :: String -> [String]
ord [] = []
ord xs = filter (not . null) ys
    where
        ys = groupBy (\x y -> y /= ' ') xs

How do i re-write this code so that i rid the list of its empty strings? Or use the proper syntax? Im just learning Haskell and im still having trouble with the syntax...

2
  • 1
    There are no problems with syntax here—the compiler would tell you so. Rewrite the code to omit strings which contain only a space, and note that some strings start with a space. Commented Sep 15, 2019 at 9:28
  • 3
    If you want to use groupBy to throw all the spaces into their own groups, you need to look at x as well. Otherwise the spaces gets grouped together with the non-space after it. And null checks for empty strings (zero characters), not blank strings (only space). Commented Sep 15, 2019 at 9:28

2 Answers 2

5

groupBy means that you put x and y in the same group, given the condition is satisfied. But here you group the two together, given y is not equal to a space.

You thus can alter your grouping predicate, and put x and y in the same group, given both are spaces, or non-spaces:

import Data.Char(isSpace)

ord :: String -> [String]
ord [] = []
ord xs = let
    ys = groupBy (\x y -> isSpace x == isSpace y) xs
    in filter (not . null) ys

or shorter:

import Data.Char(isSpace)
import Data.Function(on)

ord :: String -> [String]
ord [] = []
ord xs = let
    ys = groupBy (on (==) isSpace) xs
    in filter (not . null) ys

Now we retrieve:

Prelude Data.List> ord "aa b       c   -    dd"
["aa"," ","b","       ","c","   ","-","    ","dd"]

We of course still not obtain the expected result. In stead of filtering out empty strings, we can filter out strings that only contain spacing characters:

import Data.Char(isSpace)
import Data.Function(on)

ord :: String -> [String]
ord [] = []
ord xs = let
    ys = groupBy (on (==) isSpace) xs
    in filter (not . all isSpace) ys

We do not need to covert the empty case manually, since groupBy on an empty list produces an empty list, we can thus construct a one liner to do the processing:

import Data.Char(isSpace)
import Data.Function(on)

ord :: String -> [String]
ord = filter (not . all isSpace) . groupBy (on (==) isSpace)

Then we obtain the expected result:

Prelude Data.List Data.Char> ord "aa b       c   -    dd"
["aa","b","c","-","dd"]
Sign up to request clarification or add additional context in comments.

Comments

3

I wouldn't bother with groupBy at all here. In particular, there's no need to build lists of spaces just to throw them away. Let's start with a function that drops initial spaces and then grabs everything to the first space:

grab :: String -> (String, String)
grab = break isSpace . dropWhile isSpace

Note that the first component of grab xs will be empty if and only if all the elements of xs are spaces.

Now we can write

myWords :: String -> [String]
myWords xs = case grab xs of
  ([], _) -> []
  (beginning, end) -> beginning : myWords end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.