Maybe

The Maybe monad is used when a series of computations could return nil at any point.

bind

Applies a block to a monadic value. If the value is Some then calls the block passing the unwrapped value as an argument. Returns itself if the value is None.

require 'dry-monads'

M = Dry::Monads

maybe_user = M.Maybe(user).bind do |u|
  M.Maybe(u.address).bind do |a|
    M.Maybe(a.street)
  end
end

# If user with address exists
# => Some("Street Address")
# If user or address is nil
# => None()

# You also can pass a proc to #bind

add_two = -> (x) { M.Maybe(x + 2) }

M.Maybe(5).bind(add_two).bind(add_two) # => Some(9)
M.Maybe(nil).bind(add_two).bind(add_two) # => None()

fmap

Similar to bind but works with blocks/methods that returns unwrapped values (i.e. not Maybe instances).

require 'dry-monads'

Dry::Monads::Maybe(user).fmap(&:address).fmap(&:street)

# If user with address exists
# => Some("Street Address")
# If user or address is nil
# => None()

value!

You always can extract the result by calling value!. It will raise an error if you call it on None. You can use value_or for safe unwrapping.

require 'dry-monads'

Dry::Monads::Some(5).fmap(&:succ).value! # => 6

Dry::Monads::None().fmap(&:succ).value!
# => Dry::Monads::UnwrapError: value! was called on None

value_or

Has one argument, unwraps the value in case of Some or returns the argument value back in case of None. It’s a safe and recommended way of extracting values.

require 'dry-monads'

M = Dry::Monads

add_two = -> (x) { M.Maybe(x + 2) }

M.Maybe(5).bind(add_two).value_or(0) # => 7
M.Maybe(nil).bind(add_two).value_or(0) # => 0

M.Maybe(nil).bind(add_two).value_or { 0 } # => 0

or

The opposite of bind.

require 'dry-monads'

M = Dry::Monads

add_two = -> (x) { M.Maybe(x + 2) }

M.Maybe(5).bind(add_two).or(M.Some(0)) # => Some(7)
M.Maybe(nil).bind(add_two).or(M.Some(0)) # => Some(0)

M.Maybe(nil).bind(add_two).or { M.Some(0) } # => Some(0)