ceno980
ceno980

Reputation: 2011

Haskell: Understanding the bind operator (>>=) for Monads

I have the following function:

parse :: String -> Maybe Token

And I am trying to implement the following function:

maketokenlist :: String -> Maybe [Token]

The function returns Nothing if there is a token that was not able to be parsed (i.e. parse returns Nothing if the token is not an integer or an arithmetic operator), otherwise it returns a list of Tokens.

As Maybe is an instance of the Monad type class, I have the following approach:

maketokenlist str =  return (words str) >>= parse

I convert the string into a list of individual tokens (e.g. "2 3 +" becomes ["2","3","+"] , and then map the parse function over each string in the list.

Since the Monad instance for lists is defined as:

instance Monad [] where
   return x = [x] 
   xs >>= f = concat (map f xs)
   fail _ = []

However, say that I had the list of strings [2, 3, "+", "a"] and after mapping parse over each element using >>= I get [Just 2, Just 3, Just (+), Nothing], as "a" cannot be parsed. Is there a way to make the function maketokenlist return Nothing using just the >>= operator? Any insights are appreciated.

Upvotes: 2

Views: 319

Answers (1)

Daniel Wagner
Daniel Wagner

Reputation: 152682

If parse :: String -> Maybe Token, then:

traverse parse :: [String] -> Maybe [Token]

This version of traverse (which I have specialized to act on lists as the Traversable instance and Maybe as the Applicative instance) may indeed be implemented using (>>=):

listMaybeTraverse parse [] = pure []
listMaybeTraverse parse (s:ss) =
    parse s >>= \token ->
    listMaybeTraverse parse ss >>= \tokens ->
    pure (token:tokens)

I have chosen the names parse, s, and token to show the correspondence with your planned usage, but of course it will work for any appropriately-typed functions, not just parse.

The instance of Monad for lists does not make an appearance in this code.

Upvotes: 4

Related Questions