Prev: The Error monad TOC: Contents Next: The IO monad

The List monad


Overview

Computation type: Computations which may return 0, 1, or more possible results.
Binding strategy: The bound function is applied to all possible values in the input list and the resulting lists are concatenated to produce a list of all possible results.
Useful for: Building computations from sequences of non-deterministic operations. Parsing ambiguous grammars is a common example.
Zero and plus: [] is the zero and ++ is the plus operation.
Example type: [a]

Motivation

The List monad embodies the strategy of combining a chain of non-deterministic computations by applying the operations to all possible values at each step. It is useful when computations must deal with ambiguity. In that case it allows all possibilities to be explored until the ambiguity is resolved.

Definition

instance Monad [] where
    m >>= f  = concatMap f m
    return x = [x]
    fail s   = []
    
instance MonadPlus [] where
    mzero = []
    mplus = (++)

Example

The canonical example of using the List monad is for parsing ambiguous grammars. The example below shows just a small example of parsing data into hex values, decimal values and words containing only alpha-numeric characters. Note that hexadecimal digits overlap both decimal digits and alphanumeric characters, leading to an ambiguous grammar. "dead" is both a valid hex value and a word, for example, and "10" is both a decimal value of 10 and a hex value of 16.

Code available in example13.hs
-- we can parse three different types of terms
data Parsed = Digit Integer | Hex Integer | Word String deriving Show

-- attempts to add a character to the parsed representation of a hex digit
parseHexDigit :: Parsed -> Char -> [Parsed]
parseHexDigit (Hex n) c = if isHexDigit c then
                            return (Hex ((n*16) + (toInteger (digitToInt c))))
                          else
                            mzero
parseHexDigit _       _ = mzero

-- attempts to add a character to the parsed representation of a decimal digit
parseDigit :: Parsed -> Char -> [Parsed]
parseDigit (Digit n) c = if isDigit c then
                           return (Digit ((n*10) + (toInteger (digitToInt c))))
                         else
                           mzero
parseDigit _         _ = mzero
		   
-- attempts to add a character to the parsed representation of a word
parseWord :: Parsed -> Char -> [Parsed]
parseWord (Word s) c = if isAlpha c then
                         return (Word (s ++ [c]))
                       else
                         mzero
parseWord _        _ = mzero

-- tries to parse the digit as a hex value, a decimal value and a word
-- the result is a list of possible parses
parse :: Parsed -> Char -> [Parsed]
parse p c = (parseHexDigit p c) `mplus` (parseDigit p c) `mplus` (parseWord p c)

-- parse an entire String and return a list of the possible parsed values
parseArg :: String -> [Parsed]
parseArg s = do init <- (return (Hex 0)) `mplus` (return (Digit 0)) `mplus` (return (Word ""))
                foldM parse init s

Prev: The Error monad TOC: Contents Next: The IO monad