Haskell’s Binding Operator (>>=) Simple For F# Programmers

Although not strictly necessary, to be a good F# programmer you pretty much have to learn Haskell.  It reminds me of the relationship between VB and C#.  Sure, you don’t have to learn C#, but you miss out on so much good knowledge and know how if you don’t.  Without C#, you can be an ok VB programmer, but you will never be a good VB programmer.

I don’t believe it’s possible to learn monads knowing only F#.  You quickly realize everybody who already understands them speaks a different language and that language is Haskell.

So let’s make Haskell easy to understand for F# programmers.

The Binding Operator (>>=)

The first symbol you will encounter when trying to learn monads is Haskell’s binding operator (>>=).  While reading this Wikipedia article I kept getting hung up on what exactly it’s doing. It wasn’t until I found this article that the light went on.  Let’s start with a symbol we all know and love.

 

let (|>) (p : ‘a) (f : ‘a -> ‘b) = f p

let f p = p + p

let g p = p / p

let h p = p – p

let result = 0 |> f |> g |> h

 

The pipe operator simply pipes the results of one function on to the next.

 

let result = 0 |> f |> g |> h

 

can be read as

 

let result = h ( g (f 0)))

 

The (>>=) can be thought of as doing the same thing.  It pipes the results from one function on to the next.

 

let result = 0 >>= f >>= g >>= h

 

The cool thing about the (>>=) operator is we get to define what we want to happen at each pipe step.  This comes in handy because if you run the above code a division by zero exception gets thrown.  The universe just don’t like dividing by zero.

The Maybe Monad the Haskell way

Last time we created a Maybe monad the F# way.  This time we’ll define a more Haskellesque version.

 

type Maybe<’a> = option<’a>

let unit x = Some(x) : Maybe<’a>

let (>>=) (p : Maybe<’a>) (f : ‘a -> Maybe<’b>) : Maybe<’b> =

    match p with

        | None -> None

        | Some r -> f r

 

We’ve used unit instead of return because return is a reserved word in F#.  When you’re not using computation expression syntax unit actually makes more sense than return.  The unit function maps the underlying type to our Monadic type.  Now we’ll redefine our f g and h functions to use the maybe monad instead of integers.

 

let fm p = unit (p + p)

let gm p = if p = 0 then None else unit (p / p)

let hm p = unit (p – p)

 

Notice how gm now checks whether p is zero before doing the division.  And now we use our smart pipe operator to propagate our wrapped result from function to function.

 

let result = unit 0 >>= fm >>= gm >>= hm

 

The universe is now happy, no more divide by zero exception.  At each step, the maybe monads smart pipe operator (>>=) gets a chance to interrupt the result and either continue the operation or halt.  The downside is we had to rewrite our f g and h functions to explicitly work with the monad type.

    

Now that we understand Haskell’s (>>=) operator and unit/return function, next time we’ll make the do notation just as easy.

Full source

Here’s the full source code for reference.  When I first wrote this I didn’t realize that operators can be used infix by removing the parenthesis around them.  I thought I’d keep my original pipe and bind functions in the source because they’re just kind of interesting, and lispy.

 

#light

 

let pipe (p : ‘a) (f : ‘a -> ‘b) = f p

let (|>) (p : ‘a) (f : ‘a -> ‘b) = f p

let f p = p + p

let g p = p / p

let h p = p – p

 

let result = 0 |> f |> g |> h

let result1 = pipe (pipe (pipe 0 f) g) h

 

type Maybe<’a> = option<’a>

let unit x = Some(x) : Maybe<’a>

let bind (p : Maybe<’a>) (f : ‘a -> Maybe<’b>) : Maybe<’b> =

    match p with

        | None -> None

        | Some r -> f r

let (>>=) (p : Maybe<’a>) (f : ‘a -> Maybe<’b>) : Maybe<’b> =

    match p with

        | None -> None

        | Some r -> f r

 

let fm p = unit (p + p)

let gm p = if p = 0 then None else unit (p / p)

let hm p = unit (p – p)

 

let result2 = unit 0 >>= fm >>= gm >>= hm

let result3 = bind (bind (bind (unit 0) fm) gm) hm

printfn “%A” result2

System.Console.ReadLine()

System.Console.ReadLine()

10 comments to Haskell’s Binding Operator (>>=) Simple For F# Programmers

  • BMeph

    I see you’re not using that result3…

    …mind if I borrow it? ;)

  • Cale Gibbard

    There’s just one problem with this approach to explaining monads: the monad abstraction is completely pointless unless you can write code which works in more than one monad.

    While you might get some benefit from having >>= just for the Maybe type, the real benefit of recognising that Maybe is a monad comes from the libraries of functions which are abstracted over an *arbitrary* monad, which suddenly start working with Maybe values once you define it as a monad. Without that ability to abstract over which monad one is working with, it’s hard to be convincing that monads are actually a useful concept.

    However, I’m a Haskell programmer and haven’t taken a really close look at F#, since I don’t have a Windows machine handy, so I’m not altogether sure what abstractions it supports to help here. If it supports (constructor) typeclasses, then you would definitely want to use those, but somehow I have the impression that it doesn’t. If it has a module system which is anything like SML/O’Caml, then you’d probably want to make full use of that, though it’s somewhat clunkier for code in which more than one monad is involved. If it has neither, then in order to get a similar level of abstraction, bind and return and everything constructed from them must take another parameter (which you’d generally take to be a dictionary consisting of the monad operations).

  • josh

    Of course it’s similar to Haskell… You’ve never heard that F# is an almost exact copy of Ocaml?

  • mattdoig

    Excellent points Cale. I agree that the .Net family of languages have monadic influences, but that they are not ture monads. The .Net languages do not support operations like lift or when and obviously without lift transformers are not a possibility.

    I think the important point is that the .Net community is starting to grasp the importance of immutability, composition, and separation of side effects.

    There’s nothing stopping somebody writing a .Net library with Monad as the base class. How similar are .Net classes to Haskell type classes. I’m not certain of this yet, but it’s something I plan on examining.

  • mattdoig

    Josh, yes i know F# is a derivative of OCaml. How similar it is to Haskell is open to debate however. F# is a pass by value language and not a lazy. F# is not a pure functional language. F# runs as IL instructions on a virtual common language runtime.

    I beleive the goal of F# is to create a useful, pragmatic, high level, functional language for .Net programmers. Haskell will never fly where i work, but F# will. I’m sure this is true of most small companies creating software on the Windows stack.

  • mattdoig

    BMeph,

    You are very welcome to use it. Just don’t use if i’m working on a project with you!

  • hmmm…..

    I am an OCaml programmer and have only a passing understanding of Haskell. Whilst monads are bolted in haskell it doesn’t mean they do not make sense elsewhere. You can learn them without learning haskell; and even then, a basic understanding of ML should be enough to carry you through the haskell tutorials.
    F# is a bit more haskelly (Don Syme works in the same building as SPJ so this should be expected) but I would argue the language you actually need to understand is C#.
    F# integrate abstractions that can hide some of the OO underpinning; a solid understanding of C# class systems comes in handy when you are exploring darker corners (and these abstractions fail).

  • [...] the comments of the last post, Cale Gibbard noted that the monad abstraction is pointless unless you can write code that works [...]

  • [...] point using the existing sugaring.  Others have taken different angles such as such as with simple operators and template expansion, but in this case, I don’t think that’s enough to help.  Instead, [...]

  • [...] point using the existing sugaring.  Others have taken different angles such as such as with simple operators and template expansion, but in this case, I don’t think that’s enough to help.  Instead, [...]

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>