Skip to content

Instantly share code, notes, and snippets.

@pithyless
Created March 27, 2012 14:44
Show Gist options
  • Select an option

  • Save pithyless/2216519 to your computer and use it in GitHub Desktop.

Select an option

Save pithyless/2216519 to your computer and use it in GitHub Desktop.

Revisions

  1. pithyless revised this gist Mar 27, 2012. 1 changed file with 16 additions and 0 deletions.
    16 changes: 16 additions & 0 deletions examples.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@

    def controller

    res = ParseParam.call(params)
    res = res >> lambda { |res| DoSomeStuff.call(res) }
    res = res >> lambda { |res| FinickyThirdParty.call(res) }
    res = res >> ...
    res.to_xml

    end

    # If this seems like a good idea, we can add a little bit of sugar:

    res = Either.right('ok')
    res >>= JustAnotherProc

  2. pithyless revised this gist Mar 27, 2012. 1 changed file with 20 additions and 0 deletions.
    20 changes: 20 additions & 0 deletions either.rb
    Original file line number Diff line number Diff line change
    @@ -36,6 +36,26 @@ def >>(callable)
    end
    end

    # Short-circuit applicative AND
    #
    # Examples
    #
    # Either.right(1) & Either.right(2) & Either.right(3)
    # #=> #<Either: @left=nil, @right=3>
    #
    # Either.right(1) & Either.left(2) & Either.right(3)
    # #=> #<Either: @left=2, @right=nil>
    #
    # Returns either the first Left or the last Right
    def &(other)
    fail "Expected Either; got #{other.inspect}" unless other.is_a?(Either)
    if left?
    self
    else
    other
    end
    end

    def self.left(left)
    new(left, nil)
    end
  3. pithyless revised this gist Mar 27, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion either.rb
    Original file line number Diff line number Diff line change
    @@ -28,7 +28,7 @@ def right?

    def >>(callable)
    if left?
    Either.left(left)
    self
    else
    callable.call(right).tap do |e|
    fail "No quantum leaps allowed! Expected Either; got #{e.inspect}" unless e.is_a?(Either)
  4. pithyless created this gist Mar 27, 2012.
    47 changes: 47 additions & 0 deletions either.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,47 @@
    # A chainable Either monad for Ruby
    #
    # Examples
    #
    # Either.right('s') >> proc { |s| Either.right(s + '-1') } >> proc { |s| Either.right(s + '-2') }
    # #=> #<Either @left=nil, @right="s-1-2">
    #
    # Either.right('s') >> proc { |s| Either.left('error!') } >> proc { |s| Either.right(s + '-2') }
    # #=> #<Either @left='error!', @right=nil>
    #
    # Returns either left or right.
    class Either
    attr_reader :left, :right
    private_class_method :new

    def initialize(left, right)
    @left = left
    @right = right
    end

    def left?
    !!left
    end

    def right?
    not left?
    end

    def >>(callable)
    if left?
    Either.left(left)
    else
    callable.call(right).tap do |e|
    fail "No quantum leaps allowed! Expected Either; got #{e.inspect}" unless e.is_a?(Either)
    end
    end
    end

    def self.left(left)
    new(left, nil)
    end

    def self.right(right)
    new(nil, right)
    end

    end