4 ms·
You're probably being downvoted for being sarcastic about a good thing (at least... I think that's sarcasm?). Independently discovering Option.map and realizin
by Strilanc 13y ago
You're probably being downvoted for being sarcastic about a good thing (at least... I think that's sarcasm?).
Independently discovering Option.map and realizing its usefulness is good. Point at the existing work instead of making fun.
http://en.wikipedia.org/wiki/Option_type http://en.wikipedia.org/wiki/Option_type (well.. maybe a bit more introductory than that..)
- DanWaterworth 13y agoI didn't mean to come off sarcastic. Though, reading it back, I can see how you could have thought that. I'm enthusiastic whenever anyone inadvertently discovers functional concepts.
- akkartik 13y agoCan you elaborate? I don't see how this pattern is a monad.
- pestaa 13y agoIt is a sequence. Step 1: find something. Step 2: if it is found, do something with it, and optionally find another thing based on that result. Sounds like programmable semicolon, or a monad, to me.
- DanWaterworth 13y agoIt's not quite defining a monad, but it's very close. The example given in the article is: data_source.person(id) do |person| person.phone_number = phone_number data_source.update_person person end You can abstract this pattern a little by putting it in a function: def maybe_bind(x, &blk) if !x.nil? blk.call(x) else nil end end Now consider the type of this function: nil or X, (X -> nil or Y) -> nil or Y A monad is any type for which you can define bind and return. They have the Haskell types: bind :: m a -> (a -> m b) -> m b return :: a -> m a "maybe_bind" is very similar to "bind"; just replace "m" with "nil or" and uncurry. "return" is trivial to implement.
- tmoertel 13y agoThe 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
- tome 13y agoThe pattern as presented doesn't actually use the monad instance, just the functor instance, because there's no sequencing of actions involved here, there's just one action (update or not).