10

I was doing a presentation on F# and was discussing the Option type when someone in the audience asked me if the Option type is F#'s implementation of the maybe monad. I know that's not the case but I did want to ask how the two concepts are related. I mean it seems to me that an option type might be the result of the operation of a maybe monad but I'm not even sure of that.

Would someone elucidate the relationship between the maybe monad and the option type in those functional languages which support it?

Onorio Catenacci
  • 2,977
  • 3
  • 28
  • 38

3 Answers3

12

Reading the documentation on F#'s Option type, it looks like it does behave pretty much exactly like the Maybe type in Haskell, in that it can model either 'nothing' (None in F#, Nothing in Haskell), or a value of its argument type (Some in F#, Just in Haskell).

In Haskell, however, Maybe is also a monad, and the plumbing is such that it allows for calculations on Maybe values, early-returning Nothing if any of the variables in the calculation is Nothing. Used this way, Maybe is a simple error handler (or rather, error-ignoring device), and the fact that it is a monad allows moving the boilerplate out of the way. Look at this wikipedia article for a nice concise example. I don't think Option supports this kind of monadic usage (in fact, I'm wondering whether there is any explicit concept of a monad in F# at all). If you want this behavior in .NET, I guess you'd use Option.Value for all your arguments, and wrap the whole calculation in a try / catch on NullReferenceException.

So, while Option is similar to the Maybe type, it is not an equivalent to the Maybe monad.

tdammers
  • 52,936
10

Yes, they're equivalent in the sense that the Option type together with Option.bind and type constructor Some constitute a monad.

While monads (as in the Monad typeclass) are a central part of Haskells identity, from a conceptual point of view they're a language-agnostic construct. A design pattern if you like. If you have a type, and you have a bind and a return function with specific signatures that obey a particular set of laws - you have a monad - regardless of the language you use.

F# computation expressions only provide a programmable syntax sugar for monads, similar to the do notation in Haskell. While there's no Option computation expression builder provided out of the box, you can easily define a bare-bones one like this:

type OptionBuilder () = 
    member this.Bind(m, f) = Option.bind f m
    member this.Return(a) = Some a 

let option = OptionBuilder ()  

And use it like this:

let c = 
    option {
        let! a = Some 4
        let! b = None
        return a + b
    }

which is a sugared equivalent of something like this:

let c =
    (Some 4) 
    |> Option.bind (fun a ->
        None 
        |> Option.bind (fun b ->
             Some (a + b)))

Note how the builder members mirror the Monad typeclass, and how you can write monadic - even if convoluted - code without a builder.

scrwtp
  • 4,542
4

They're equivalent, and they're both monads. The difference is being a monad means something in Haskell - there's an explicit Monad typeclass and "do notation" can be used to eliminate a lot of boilerplate when writing monadic code. In F#, builder notation and let! and do! can be used to get rid of similar boilerplate, but there is not an explicit notion of a type "being a monad". Haskell's type system includes typeclasses (of which the general Monad class is) and higher kinded types (of which an individual Monad is), which allow writing code that works for all monads. F#'s type system has neither of these features.

So yes, F#'s Option and Haskell's Maybe are identical and both monads. It's just that Haskell gives you a lot more machinery to work with monads than F# does.

Jack
  • 4,539