The Maybe Monad In Ruby


Just for fun, I decided to see what a monad would look like in ruby. I chose to use the Maybe monad since that’s what I used in my previous post on monads in C#. Here’s what I came up with:

   1: class Maybe

   2:   attr_accessor :value

   3:  

   4:   def initialize(value)

   5:     @value = value

   6:   end

   7:  

   8:   def get

   9:     if @value.nil?

  10:       nil.to_maybe

  11:     else

  12:       yield(@value).to_maybe unless @value.nil?

  13:     end

  14:   end

  15: end

  16:  

  17: class Object

  18:   def to_maybe

  19:     Maybe.new self

  20:   end

  21: end

  22:  

  23: class Foo

  24:   attr_accessor :bar

  25: end

  26:  

  27: class Bar

  28:   attr_accessor :baz

  29: end

  30:  

  31: foo1 = Foo.new

  32: foo1.bar = Bar.new

  33: foo1.bar.baz = "something"

  34:  

  35: foo2 = Foo.new

  36: foo2.bar = nil

  37:  

  38: result1 = foo1.to_maybe

  39:   .get{|f| f.bar}

  40:   .get{|b| b.baz}

  41:   .value || "nothing"

  42:  

  43: result2 = foo2.to_maybe

  44:   .get{|f| f.bar}

  45:   .get{|b| b.baz}

  46:   .value || "nothing"

  47:  

  48: puts "#{result1}" #=> something

  49: puts "#{result2}" #=> nothing

</div> </div>

I find this code to be much easier to read and understand than the C# version even though the C# version makes a few of the monad formulae a little more apparent. For example, the binding function formula of (M t) –> (t –> M u) –> (M u) is fairly apparent when you look at a C# method signature like this:

   1: public Maybe<TResult> Get<TInput, TResult>(Maybe<TInput> maybe, Func<TInput, TResult> func) { ... }

</div> </div>

In the ruby version, you don’t have the type declarations or the return value declaration, which gives us a little less of an immediate understanding that we are dealing with a monad. However, the tradeoff for this is that you get to keep your code very simple and you get to keep all of the binding functions for a given monad in the monads wrapper class. I’ve only implemented a get binding method, but you should be able to translate the other methods from the C# code fairly easily, using this example.

One thing I did not need to implement in the ruby version was a return method with a default value as a parameter. Remember in the C# version how we wanted to either return the value stored in the monad wrapper or some default value is the monad wrapper did not container one? Well, it turns out the || operator in ruby gives us this functionality without having to create a special to do that. On line 41 when I call .value || “nothing”, this is the equivalent of calling the .Return(someDefault) method in the C# version.

I suppose it’s not strictly necessary to add the .to_maybe method to the Object class, though. We could create a module to mix in to a specific object that we want, or we could just use the Maybe.new initializer… I put this method in there to make the final method chaining closer to the C# code that I started with. Perhaps that’s not such a wise idea, but I don’t know if it’s a bad idea or not… it works and it makes it easy to work with a maybe monad.

 

Handling Nil In Chained Calls: For @bennage

In the process of implementing and testing this, I remembered a conversation that I had with Christopher Bennage about a month and a half ago (no, my memory of the date isn’t that good… i have the IM logs, still 🙂 ) where he was asking about a way to not throw exceptions when a nil is encountered in a chained call, in ruby. He wanted to write code like this:

   1: foo = bar.baz.widget.weeble.wobble

</div> </div>

and have the code execute without error, even if baz or widget or any other part of the chain was nil. We discussed several options at the time, one of which involved a lot of nested blocks:

   1: def check(foo)

   2:   yield(foo) unless foo.nil?

   3: end

   4:  

   5: check(myvar){|x| check(x.y){|y| y.z }}

</div> </div>

This works, but it’s a bit ugly to read and difficult to understand with all the nested blocks – especially when you get more than 2 or 3 items deep.

I also came up with a horrible, horrible way of using method_missing on the nil class to get it done… but it wasn’t a good solution. If you’d like to see what it was that I came up with, it’s available on this gist. Please, please, PLEASE do NOT use this code… it’s awful.

I think the maybe monad is what he was looking for, in the end. It’s not chained call syntax of “foo.bar.baz…”, but it gets the job done in a fairly elegant manner.

 

Is There A More Idiomatic Way To Do Monads In Ruby?

I haven’t actually done any searches for monads in ruby, yet. I wrote this code and this blog post “blind”, to see what I could come up with out of my own head. I’m wondering, though… is there a more idiomatic ruby way to do monads? I think I’ve incorporated a good number of ruby idioms already – especially the use of the || operator and the use of the implicit code blocks – but I’m thinking there may be more that I’m just not aware of.

A Less Ugly Switch Statement For C#