Maybe monad for crystal

What would be the maybe monad for crystal.
Here for other languages,
http://www.rosettacode.org/wiki/Monads/Maybe_monad

Unless I’m misunderstanding what the Maybe Monad is, Crystal uses Nil unions for this. For example, the return type of Array(T)#min? is T | Nil (which is the same as T?) because there’s no minimum if the Array is empty. So, in that case, T | Nil is the same as a hypothetical type Maybe(T).

3 Likes

Exactly. In Crystal map is Object#try. As an example, the code presented in the rosettacode for Ruby:

class Maybe
  def initialize(value)
    @value = value
  end
 
  def map
    if @value.nil?
      self
    else
      Maybe.new(yield @value)
    end
  end
end

Maybe.new(3).map { |n| 2*n }.map { |n| n+1 }
#=> #<Maybe @value=7>
 
Maybe.new(nil).map { |n| 2*n }.map { |n| n+1 }
#=> #<Maybe @value=nil>
 
Maybe.new(3).map { |n| nil }.map { |n| n+1 }
#=> #<Maybe @value=nil>

Becomes in Crystal:

3.try { |n| 2*n }.try { |n| n+1 }
#=> 7
 
nil.try { |n| 2*n }.try { |n| n+1 }
#=> nil
 
3.try { |n| nil }.try { |n| n+1 }
#=> nil

Look ma, no wrapper! :smile:

5 Likes

@Alain, since you brought the topic, do you want to post the example in rosettacode? (I’ll do it otherwise).

If you do, post the link and I’ll include it in the Rosetta Code list. :smiley:

3 Likes

A real Maybe ensures that Just and None are always disjoint, so Maybe(T) = T | Nil doesn’t suffice as T is nilable. A real implementation might be:

record Just(T), value : T
record None
# alias Maybe(T) = Just(T) | None

module Enumerable(T)
  def find2(& : T ->) : Just(T) | None
    each do |elem|
      return Just.new(elem) if yield elem
    end
    None.new
  end
end

def show(x)
  case x
  in Just; p x.value
  in None; puts "(none)"
  end
end

show [nil, 1].find2 { true }  # => nil
show [nil, 1].find2 { false } # => (none)

Actual monadic operations tend to manifest as noise rather than a benefit in a language like Crystal, which I imagine is why the standard library isn’t based on monads. There are probably some shards out there that provide Maybe and other true monads.

2 Likes

Fair enough, but if you stack up Maybes, in most cases you don’t care where the None comes from (otherwise, you’ll use a more informative monad).