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
|