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)
.
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!
@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.
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.
Fair enough, but if you stack up Maybe
s, in most cases you don’t care where the None
comes from (otherwise, you’ll use a more informative monad).