1

I'm trying to implement a function which converts a string to a list of Maybe Ints, e.g. readInts "1 2 42 foo" = [Just 1,Just 2,Just 42,Nothing].

My first aproach was:

readInts (s::String) = do {
    ws <- words s;
    return (map (readMaybe::(String -> Maybe Int)) ws)
}

This resulted in the following error:

lab_monad.hs:20:52:
    Couldn't match type ‘Char’ with ‘[Char]’
    Expected type: [String]
      Actual type: String
    In the second argument of ‘map’, namely ‘ws’
    In the first argument of ‘return’, namely
      ‘(map (readMaybe :: String -> Maybe Int) ws)’
Failed, modules loaded: none.

What I tried next (and worked), was:

readInts (s::String) = do {
    let ws = (words s) in do
        return (map (readMaybe::(String -> Maybe Int)) ws)
} 

My question here is, words s obviously is of type [String]. Why does the interpreter say it is a String? What am I not understanding about <- operator?

Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • 1
    Why are you trying to use `do` notation here in the first place? – Thomas Mar 18 '18 at 17:35
  • To learn how to use the `do` notation, even if it is not the best solution here. – Tomasz Garbus Mar 18 '18 at 17:37
  • 1
    @TomaszGarbus `do`-notation is completely irrelevant to what you're trying to do here. I recommend reading [the relevant LYAH chapter](http://learnyouahaskell.com/a-fistful-of-monads), since a full explanation of Monads and `do`-notation is too broad for one question. – AJF Mar 18 '18 at 17:39
  • It's not completely irrelevant; it's just incorrectly mixing monadic operations and `map`. – chepner Mar 18 '18 at 19:46
  • Potentially relevant: https://stackoverflow.com/questions/28624408/equal-vs-left-arrow-symbols-in-haskell – chi Mar 18 '18 at 22:03

1 Answers1

5

ws <- words s, in the list monad, nondeterministically assigns one word from words s to ws; the remaining code simply works with that one word, and the return function "magically" combines the results of working on all the words into the result list.

readInts s = do
   ws <- words s  -- ws represents *each* word in words s
   return (readMaybe ws)

The do notation is just syntactic sugar for using monadic bind:

readInts s = words s >>= (\ws -> return (readMaybe ws))

Without using the Monad instance for lists, you can use map to apply the same function to each word.

readInts s = map readMaybe (words s)

let, on the other hand, simply provides a name for a more complicated expression to be used in another expression. It can be considered syntactic sugar for defining and immediately applying an anonymous function. That is,

let x = y + z in f x

is equivalent to

(\x -> f x) (y + z)
  ^     ^      ^
  |     |      |
  |     |      RHS of let binding
  |     part after "in"
  LHS of let binding

A let statement with multiple bindings is equivalent to nested let statements:

let x = y + z
    a = b + c
in x + a

is equivalent to

let x = y + z
in let a = b + c
   in x + a

which desugars to

(\x -> (\a -> x + a)(b + c))(y + z)
chepner
  • 497,756
  • 71
  • 530
  • 681