Hacker News new | past | comments | ask | show | jobs | submit login

I guess I'm missing what's specifically monadic about it. Isn't it just an algebraic data type with two alternatives? In ML you declare the morally-equivalent "option" type as:

  datatype 'a option = NONE | SOME of 'a
It's possible that the Haskell Maybe monad is doing some additional magic, but I didn't get that from this article if so (does it have something that lets you avoid manually pattern-matching on the two cases and/or using accessors?).



    Just 1 >> Nothing >> Just 3
      => Nothing

    Just 1 >> Just 2 >> Just 3
      => Just 3
To answer your last question, yes. It basically adds short-circuiting.


Haskell has that exact same definition for its Maybe type here [1]:

  data Maybe a = Nothing | Just a
After which it defines the monad operations on that type

  instance Monad Maybe where
    [...]
This says "the Maybe type is a monad", but the Maybe type could exist and be used without this, as I gather you're familiar with from ML.

When you use it a bare type, every time in your code you use a Maybe, you have to manually check for Nothing and extract the value in Just. And you can't compose functions involving Maybe without either letting Maybe bleed into the input types of functions where it is not necessary, or writing some clever wrappers (which will probably actually end up defining a monad).

Using Maybe in this way has a common structure:

  f :: Maybe a -> Maybe b
  f Nothing   = Nothing
  f (Just x)  = Just (do something with x)
Pass on Nothing from Nothing, apply the internal logic of the function if there's Just something. We can abstract this out, meaning we can write functions (a -> Maybe b), and compose them to take care of the Just/Nothing check. We can also do other things, like take functions with no knowledge of Maybe and "lift" them from (a -> b) to (Maybe a -> Maybe b). Here's the simplest expression of this abstraction:

  wrapMaybe :: Maybe a -> (a -> Maybe b) -> Maybe b
  wrapMaybe Nothing f  = Nothing
  wrapMaybe (Just x) f = f x
... this is bind for Maybe, the dreaded (>>=) that scares people away from Haskell.[2] It's half the definition of the Maybe monad:

  instance Monad Maybe where
    Nothing  >>= f  = Nothing
    (Just x) >>= f  = f x
    return x        = Just x
It's known as a monad because monads are a further abstraction, expressing a structure in common with other patterns than Maybe:

  class Monad m where:
    (>>=)   :: m a -> (a -> m b) -> m b    -- (AKA bind)
    return  :: a -> m b
Just by defining these two functions for a type (in this case the Maybe type), a bunch of higher-order functions, like the "lifting" I mentioned, and composition of monadic functions similar to composition of normal functions, and composition of monads to stack the effects they represent, are already defined, derived from these two functions (return and bind/>>=), taking advantage of having the monadic structure in common.

What seems trivial with Maybe as a monad is that "return", the other part of defining a monad, is just the data constructor Just, whereas in other monads it's more complicated.

---

EDIT: I had previously defined: (Just x) >>= f = Just (f x) -- this is actually fmap for Maybe, which is also the lifting function I mentioned

[1] http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4...

[2] Forgive me, it is at this point that I realize you may actually know all about monads and were just wondering what's monadic about Maybe. But I was already too deep into Writing A Monad Tutorial to throw it away. Incidentally,

NB: I've never actually exposed my tentative understanding of monads in public before, so before trying to follow anything I've said here, wait on someone on surer ground to pipe up with approval (or criticism, which I would very much appreciate).


Also

    fmap :: (Functor f) => (a -> b) -> f a -> f b
    fmap f (Just x) = Just (f x)
So

    fmap (\x -> x * x) (Just 4)
       => Just 16

Am I correct in saying that `fmap` is a functor which lifts the first argument `f` into the monad and then applies it to the second argument?


WARNING: This is the blind leading the blind. I was already well-upvoted for my previous post before realizing (thanks to you, tkahn) that my definition of bind was actually fmap (I think). Crying out for authority here; help us out HN.

---

You are not, strictly/pedantically speaking, because fmap is the single function that defines a Functor to begin with [1]:

  class Functor f where
    fmap :: (a -> b) -> f a -> f b
and Monads are a special case of Functors; so, as the defining relation of a Functor, it doesn't a priori have anything to do with Monads.

You are right in seeing that fmap is lifting -- liftM, which is defined in terms of just bind and return for Monads, is (I believe... see warning above) identically fmap. fmap = map for Lists as seen as Functors, for example, which lifts a function (a -> b) to ([a] -> [b])... "into" the Functor/Monad, I suppose.

---

[1] http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4...


All Monads are, in theory if not in practice, Functors (there happens to be an instance of Functor defined for Maybe). fmap is not a functor but an arrow, in this case a function, that lifts f into the context of the Functor.


Would something like

   lift f = (return . f)
Be a functor?

[Edit: It says on Wikipedia that a functor maps a function in one category to a function in another category]


A monad is just a container with some operations to work indirectly with its contents.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: