Module: Either

Includes:
Comparable, Control::Monad, UnionType
Included in:
Left, Right
Defined in:
lib/data.either.rb

Overview

‘Either a b` is either `Left a` or `Right b`

Class Method Summary collapse

Instance Method Summary collapse

Methods included from UnionType

#when

Methods included from Helper

#alias_names

Methods included from Control::Monad

#>>

Methods included from Control::Applicative

#apply

Class Method Details

.lefts(list_of_either) ⇒ value

filter only Left value from List of Either

“‘ ruby Either.lefts [Left.new(1),Right.new(5), Right.new(2)] # => [1] “`

Returns:

  • (value)


205
206
207
208
# 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

.partition(list_of_either) ⇒ [l], [r]

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]] “`

Returns:

  • ([l], [r])


216
217
218
219
220
221
222
# 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

.rights(list_of_either) ⇒ value

filter only Right value from List of Either

“‘ ruby Either.rights [Left.new(1),Right.new(5), Right.new(2)] # => [5, 2] “`

Returns:

  • (value)


194
195
196
197
# 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

.tryEither

try something could raise exception, and wrap value into Right, exception into Left

“‘ruby Either::try do

something_may_raise_error

end “‘

Returns:



19
20
21
22
23
# File 'lib/data.either.rb', line 19

def self.try
  Right.new(yield)
rescue => e
  Left.new(e)
end

Instance Method Details

#<=>(other) ⇒ Object

comparable

  • Left < Right



166
167
168
169
170
171
172
173
174
175
# File 'lib/data.either.rb', line 166

def <=>(other)
  other =~ case self
           when Right
             { Right: ->(o) { @v <=> o },
               Left: ->(_) { 1 } }
           else
             { Right: ->(_) { -1 },
               Left: ->(o) { @v <=> o } }
           end
end

#bimap(lfn, rfn) ⇒ Either

‘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

“‘

Returns:



106
107
108
109
110
111
112
113
# 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

#each(&block) ⇒ Object



151
152
153
# File 'lib/data.either.rb', line 151

def each(&block)
  bimap(->(_) {}, &block)
end

#flat_mapEither

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)) “`

Returns:



125
126
127
128
129
130
131
132
# File 'lib/data.either.rb', line 125

def flat_map
  case self
  when Right
    yield @v
  else
    self
  end
end

#get_or_else(e) ⇒ Object Also known as: |

get value ‘a` out from `Right a`, otherwise return `e` “`ruby Right.new(1).get_or_else(2) # => 1 Right.new(1) | 2 # => 1 “`



47
48
49
50
51
52
53
54
# File 'lib/data.either.rb', line 47

def get_or_else(e)
  case self
  when Right
    @v
  else
    e
  end
end

#initialize(v = nil) ⇒ Either

Either only contain one value @v

Returns:



27
28
29
# File 'lib/data.either.rb', line 27

def initialize(v = nil)
  @v = v
end

#inspectString Also known as: to_s

Returns:

  • (String)


178
179
180
181
182
183
184
185
# File 'lib/data.either.rb', line 178

def inspect
  case self
  when Left
    "#<Left #{@v.inspect}>"
  else
    "#<Right #{@v.inspect}>"
  end
end

#left?Boolean

default ‘false`, should override in Left or Right

Returns:

  • (Boolean)


33
34
35
# File 'lib/data.either.rb', line 33

def left?
  false
end

#left_mapEither

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>

“‘

Returns:



90
91
92
93
94
95
96
97
# File 'lib/data.either.rb', line 90

def left_map
  case self
  when Left
    Left.new(yield @v)
  else
    self
  end
end

#mapEither

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>

“‘

Returns:



74
75
76
77
78
79
80
81
# File 'lib/data.either.rb', line 74

def map
  case self
  when Right
    Right.new(yield @v)
  else
    self
  end
end

#or_else(e) ⇒ Object



58
59
60
61
62
63
64
65
# File 'lib/data.either.rb', line 58

def or_else(e)
  case self
  when Right

  else
    e
  end
end

#right?Boolean

default ‘false`, should override in Left or Right

Returns:

  • (Boolean)


38
39
40
# File 'lib/data.either.rb', line 38

def right?
  false
end

#to_aObject



155
156
157
158
159
160
161
162
# File 'lib/data.either.rb', line 155

def to_a
  case self
  when Right
    [@v]
  else
    []
  end
end

#~@Either Also known as: swap

swap type of [Either]

“‘ruby

~Right.new(1) # => Left.new(1)
~Left.new(2) # => Right.new(2)

“‘

Returns:



141
142
143
144
145
146
147
148
# File 'lib/data.either.rb', line 141

def ~@
  case self
  when Right
    Left.new @v
  else
    Right.new @v
  end
end