Class: Tweed::Monad

Inherits:
Object show all
Defined in:
lib/tweed/monad.rb

Overview

Abstract superclass to represent monads.

 To create a monad, subclass and define the monad’s Kleisli triple using define_monad.

Examples:

Implementing the Maybe monad

class Maybe < Tweed::Monad
  define_monad do
    # This becomes the `initialize` instance method:
    construct { |value, success| @value, @success = value, success }

    # This becomes the `return` class method:
    unit { |value| self.new(value, true) }

    # This becomes the `bind` instance method:
    bind { |&block| @success ? block.call(@value) : self }

    # This becomes the (cached) `zero` class method:
    zero { self.new(nil, false) }
  end

  def inspect
    @success ? "Just #{@value.inspect}" : "Nothing"
  end
end

Using the Maybe monad to implement safe division

class SafeDivision < Maybe
  def /(other)
    self.bind do |x|
      other.bind do |y|
        y.zero? ? self.class.zero : self.class[x / y]
      end
    end
  end
end

x = SafeDivision[1] / SafeDivision[2.0] # => Just 0.5
y = SafeDivision[1] / SafeDivision[0]   # => Nothing

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.[](*args) ⇒ Monad

Syntactic sugar for Monad.return(…).

Returns:



60
61
62
# File 'lib/tweed/monad.rb', line 60

def self.[](*args)
  self.return(*args)
end

.return(*args) ⇒ Monad

This method is abstract.

Subclass and override using define_monad.

Lift a value into this monad.

Returns:

  • (Monad)

    the newly created monad.



48
49
50
# File 'lib/tweed/monad.rb', line 48

def self.return(*args)
  abstract
end

Instance Method Details

#bind(&block) ⇒ Object

This method is abstract.

Subclass and override using define_monad.

Pull an underlying value out of this monad.



54
55
56
# File 'lib/tweed/monad.rb', line 54

def bind(&block)
  abstract
end

#lift_m2(other) {|x, y| ... } ⇒ Object

Adaptation of ‘liftM2` from Haskell. ‘Lifts’ a binary function into the current monad.

Examples:

Add two numbers

m_x = SomeMonad[1]
m_y = SomeMonad[2]
m_z = m_x.lift_m2(m_y) { |x, y| x + y } # => SomeMonad[1 + 2] => SomeMonad[3]

Parameters:

  • other

    another value within the current monad.

Yields:

  • (x, y)

    the underlying values of ‘self` and `other`.

Returns:

  • the result of the binary operation, lifted back into the current monad.



76
77
78
79
80
81
82
# File 'lib/tweed/monad.rb', line 76

def lift_m2(other)
  self.bind do |x|
    other.bind do |y|
      self.class[yield(x, y)]
    end
  end
end