0
votes

So I am trying to program a function in haskell which does the following things: 1. Input is a string 2. function first removes all letters of the string and only numbers remain 3. function converts the string numbers to int numbers 4. function sums the numbers in the string together and prints it out

My Code til' Step #3

func str = 
    do 
    str <- filter (< 'a') str
    str2 <- map digitToInt str
    return str2

somehow this doesn't work if I remove the 4th line with map digitToInt it works til step #2 fine but I dont know what the problem here is

The Error is an couldnt match expected type [Char] with actual type Char

Thank you in advance

2
example input "45abc" output 9HaskellPlease

2 Answers

7
votes

You don't want do notation at all, just normal variable binding. So:

func str = str2 where
    str1 = filter (<'a') str
    str2 = map digitToInt str1

Tracking the most recently used name is annoying, isn't it? Plus it's easy to make a mistake and type str instead of str1 somewhere, or similar. Enter function composition:

func str = str2 where
    str2 = (map digitToInt . filter (<'a')) str

In fact, I would inline the definition of str2, then elide str entirely:

func = map digitToInt . filter (<'a')

I would prefer to use isDigit over (<'a'); we can toss in a sum at the same time.

func = sum . map digitToInt . filter isDigit

Reads nice and clean, in my opinion.

3
votes

You could use do notation, since strings are lists and lists are monads. It would look like this, though:

func :: String -> [Int]
func str = do
  c <- filter (< 'a') str  -- Get one character
  return (digitToInt c)    -- Change that character to a integer

What is the value of c? It's not just one character, but all of them. The list monad models nondeterminism. Imagine that func makes multiple copies of itself, with each copy selecting a different character c from the input string. return makes a new list from the result, and the monad takes care of glue the individual lists into a one final list. It's a little clearer if you compare it its deconstructed form.

func str = filter (< 'a') str >>= \c -> return (digitToInt c)

Since xs >>= f = concatMap f xs and return x = [x] in the Monad [] instance, it becomes:

func str = concatMap (\c -> [digitToInt c]) (filter (< 'a') str)

However, the monadic form isn't necessary, as your function only needs to make use of the Functor instance of [], since every element from the first list corresponds to exactly one element in the final list:

-- Or in a form closer to Daniel Wagner's answer
func str = fmap digitToInt (filter (< 'a') str)