3 ms·
The underlying pattern is captured by the Maybe monad. Its bind rule takes (1) a computation producing a value of type "Maybe a" and (2) a function accepting a
by tmoertel 13y ago
The underlying pattern is captured by the Maybe monad. Its bind rule takes (1) a computation producing a value of type "Maybe a" and (2) a function accepting an "a" and producing a computation producing a value of type "Maybe b". It then returns a new computation that will produce "Nothing" if the first computation produces "Nothing"; otherwise, it will take the value it received from the first computation ("Just x") and pass the value "x" to the function (2) to get a new computation, which it will then perform. Thus if either the first computation or the second produces Nothing, the result will be nothing. Further, if the first produces Nothing, the second will be short-circuited away and never evaluated.
These semantics are basically what you implement by hand when you join together computations that may produce NULL results and check for NULLs in between. But now the computer is doing the checking for you, so the checking is hidden and yet never gets forgotten.
For example, here's some Haskell code the provides a simple lookup database from names (type "a") to phone numbers (type "b"):
-- name phone number
persons = [("Joe", "123-555-7890"),
("Tom", "432-555-0987")]
The lookup service for this database may return a result, thus it returns a value of the Maybe type to indicate that it may not be able to find a "b" for every "a" you give it:
lookup :: Eq a => a -> [(a, b)] -> Maybe b
But since Maybe is a monad and its bind rule takes care of the didn't-get-a-result checking for us, we can safely string together lookup computations without having to do any checks by hand. Nevertheless, we can be assured that all the checks will be done.
For example, let's create a function that takes two persons' names, looks up their phone numbers, and (if both are found) connects them with a (simulated) call.
-- try to connect person a's phone to person b's phone
connect a b = do
phonea <- lookup a persons
phoneb <- lookup b persons
return $ "connected " ++ phonea ++ " to " ++ phoneb
If we try to connect two names that are known to our lookup service, the call goes through as expected:
*Main> connect "Tom" "Joe"
Just "connected 432-555-0987 to 123-555-7890"
But if either or both of the name lookups fail, no call is made:
*Main> connect "Tom" "SomeUnknownDude"
Nothing
*Main> connect "SomeUnknownDude" "Tom"
Nothing
*Main> connect "SomeUnknownDude" "AnotherUnknownDude"
Nothing