module Either
The `Either` union type represents values with two possibilities:
`Either a b` is either `Left a` or `Right b`
Public Class Methods
filter only {Left} value from List of {Either}
“` ruby Either.lefts
[Left.new(1),Right.new(5), Right.new(2)
] # => [1] “` @return [value]
# File lib/data.either.rb, line 205 def lefts(list_of_either) list_of_either.select(&:left?) .map { |left| left.when(Left: ->(l) { l }) } end
Either
only contain one value @v @return [Either]
# File lib/data.either.rb, line 27 def initialize(v = nil) @v = v end
partion a List of {Either} into a List of 2 List, one contains only {Left}, other contains only {Right}
“` ruby Either.partition
[Left.new(1),Right.new(5), Right.new(2)
] # => [[1],[5, 2]] “` @return [[l],]
# File lib/data.either.rb, line 216 def partition(list_of_either) list_of_either.inject([[], []]) do |acc, x| x.when(Left: ->(l) { acc[0].push(l) }, Right: ->(r) { acc[1].push(r) }) acc end end
filter only {Right} value from List of {Either}
“` ruby Either.rights
[Left.new(1),Right.new(5), Right.new(2)
] # => [5, 2] “` @return [value]
# File lib/data.either.rb, line 194 def rights(list_of_either) list_of_either.select(&:right?) .map { |right| right.get_or_else(nil) } end
try something could raise exception, and wrap value into Right
, exception into Left
@return [Either] “`ruby Either::try
do
something_may_raise_error
end “`
# File lib/data.either.rb, line 19 def self.try Right.new(yield) rescue => e Left.new(e) end
Public Instance Methods
`bimap` accept 2 lambdas, if it's [Right], apply the 2nd lambda, otherwise apply to the first lambda
“` ruby
Right.new(1).bimap ->(x){x-1}, ->(x){x+1} # => 2 Left.new(1).bimap ->(x){x-1}, ->(x){x+1}) # => 0
“` @return [Either]
# File lib/data.either.rb, line 106 def bimap(lfn, rfn) case self when Right Right.new(rfn.call(@v)) else Left.new(lfn.call(@v)) end end
# File lib/data.either.rb, line 151 def each(&block) bimap(->(_) {}, &block) end
it override {Monad#flat_map}, as Haskell's `>flat_map` method if it's {Right}, pass the value to flat_map
's block, and flat the result of the block.
when it's {Left}, do nothing “` ruby expect(Right.new(1)
.flat_map { |x| Left.new
} ).to eq(Left.new
) expect(Left.new(1)
.flat_map { |x| Left.new
} ).to eq(Left.new(1)
) “` @return [Either]
# File lib/data.either.rb, line 125 def flat_map case self when Right yield @v else self end end
get value `a` out from `Right a`, otherwise return `e` “`ruby Right.new(1)
.get_or_else(2) # => 1 Right.new(1)
| 2 # => 1 “`
# File lib/data.either.rb, line 47 def get_or_else(e) case self when Right @v else e end end
@return [String]
# File lib/data.either.rb, line 178 def inspect case self when Left "#<Left #{@v.inspect}>" else "#<Right #{@v.inspect}>" end end
default `false`, should override in {Left} or {Right} @return [Boolean]
# File lib/data.either.rb, line 33 def left? false end
the opposit of map
, apply function to `Left e`, do nothing if it's `Right a`
“` ruby
Right.new(1).left_map {|x| x + 1} # => #<Right value=1> Left.new(1).left_map {|x| x + 1} # => #<Left value=2>
“` @return [Either]
# File lib/data.either.rb, line 90 def left_map case self when Left Left.new(yield @v) else self end end
overide of Functor's `fmap`, apply function on `Right a`'s value `a`, do nothing if it's `Left e`
“` ruby
Right.new(1).map {|x| x + 1} # => #<Right value=2> Left.new(1).map {|x| x + 1} # => #<Left value=1>
“` @return [Either]
# File lib/data.either.rb, line 74 def map case self when Right Right.new(yield @v) else self end end
# File lib/data.either.rb, line 58 def or_else(e) case self when Right else e end end
(see left?
)
# File lib/data.either.rb, line 38 def right? false end
# File lib/data.either.rb, line 155 def to_a case self when Right [@v] else [] end end