data.either 0.0.5 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/control/monad.rb +23 -0
- data/lib/data.either.rb +124 -10
- data/lib/helper.rb +9 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 08f4e5166ec1ad8d037c1242ad30dc3ea9e60e4c
|
4
|
+
data.tar.gz: f3fc3a10f5aede1bc5b949b664fe65979f619785
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5f31fccf30c2341d5bfce564060eddf90172613147663f52d48e6efd301b407ed0716d282c52c6097a7dd10e247d7de5e096b834b0760ea941f796004260c605
|
7
|
+
data.tar.gz: 980bb06448d07169db9c62a1ab80b27a33bca1d7ce56019c5447f28cfadfda392fd9dc2d53aebb925ec0dbcc4a8fe831773bea65b583a77b69c6dea58fe156bd
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'helper'
|
2
|
+
module Control
|
3
|
+
module Functor
|
4
|
+
extend Helper
|
5
|
+
def map
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module Monad
|
10
|
+
extend Helper
|
11
|
+
include Functor
|
12
|
+
def >=
|
13
|
+
raise '>= No defined'
|
14
|
+
end
|
15
|
+
|
16
|
+
alias_names([:flat_map], :>=)
|
17
|
+
|
18
|
+
def > k
|
19
|
+
self.>= { |_| k }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/lib/data.either.rb
CHANGED
@@ -1,9 +1,28 @@
|
|
1
|
-
|
1
|
+
require 'control/monad'
|
2
|
+
|
3
|
+
# The `Either` union type represents values with two possibilities:
|
4
|
+
#
|
5
|
+
# `Either a b` is either `Left a` or `Right b`
|
2
6
|
module Either
|
7
|
+
include Control::Monad
|
8
|
+
|
9
|
+
# Either only contain one value @v
|
10
|
+
# @return [Either]
|
3
11
|
def initialize v
|
4
12
|
@v = v
|
5
13
|
end
|
6
14
|
|
15
|
+
# default `false`, should override in {Left} or {Right}
|
16
|
+
# @return [Boolean]
|
17
|
+
def left?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
# (see #left?)
|
21
|
+
def right?
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
# get value `a` out from `Right a`, otherwise return `e`
|
7
26
|
def get_or_else e
|
8
27
|
case self
|
9
28
|
when Right
|
@@ -13,7 +32,13 @@ module Either
|
|
13
32
|
end
|
14
33
|
end
|
15
34
|
|
16
|
-
# Functor
|
35
|
+
# overide of Functor's `fmap`, apply function on `Right a`'s value `a`, do nothing if it's `Left e`
|
36
|
+
#
|
37
|
+
# ``` ruby
|
38
|
+
# Right.new(1).map {|x| x + 1} # => #<Right value=2>
|
39
|
+
# Left.new(1).map {|x| x + 1} # => #<Left value=1>
|
40
|
+
# ```
|
41
|
+
# @return [Either]
|
17
42
|
def map
|
18
43
|
case self
|
19
44
|
when Right
|
@@ -22,9 +47,13 @@ module Either
|
|
22
47
|
self
|
23
48
|
end
|
24
49
|
end
|
25
|
-
|
26
|
-
|
27
|
-
|
50
|
+
# the opposit of #map, apply function to `Left e`, do nothing if it's `Right a`
|
51
|
+
#
|
52
|
+
# ``` ruby
|
53
|
+
# Right.new(1).left_map {|x| x + 1} # => #<Right value=1>
|
54
|
+
# Left.new(1).left_map {|x| x + 1} # => #<Left value=2>
|
55
|
+
# ```
|
56
|
+
# @return [Either]
|
28
57
|
def left_map
|
29
58
|
case self
|
30
59
|
when Left
|
@@ -34,6 +63,13 @@ module Either
|
|
34
63
|
end
|
35
64
|
end
|
36
65
|
|
66
|
+
# `bimap` accept 2 lambdas, if it's [Right], apply the 2nd lambda, otherwise apply to the first lambda
|
67
|
+
#
|
68
|
+
# ``` ruby
|
69
|
+
# Right.new(1).bimap ->(x){x-1}, ->(x){x+1} # => 2
|
70
|
+
# Left.new(1).bimap ->(x){x-1}, ->(x){x+1}) # => 0
|
71
|
+
# ```
|
72
|
+
# @return [Either]
|
37
73
|
def bimap lfn, rfn
|
38
74
|
case self
|
39
75
|
when Right
|
@@ -43,8 +79,17 @@ module Either
|
|
43
79
|
end
|
44
80
|
end
|
45
81
|
|
46
|
-
# Monad
|
47
|
-
|
82
|
+
# it override {Monad#>=}, as Haskell's `>>=` method
|
83
|
+
# if it's {Right}, pass the value to #>='s block, and flat the result
|
84
|
+
# of the block.
|
85
|
+
#
|
86
|
+
# when it's {Left}, do nothing
|
87
|
+
# ``` ruby
|
88
|
+
# expect(Right.new(1).>= { |x| Left.new } ).to eq(Left.new)
|
89
|
+
# expect(Left.new(1).>= { |x| Left.new } ).to eq(Left.new(1))
|
90
|
+
# ```
|
91
|
+
# @return [Either]
|
92
|
+
def >=
|
48
93
|
case self
|
49
94
|
when Right
|
50
95
|
yield @v
|
@@ -53,9 +98,26 @@ module Either
|
|
53
98
|
end
|
54
99
|
end
|
55
100
|
|
56
|
-
|
57
|
-
|
101
|
+
# similar to Scala's `match` for case class
|
102
|
+
#
|
103
|
+
# will pattern match the value out and pass to matched lambda
|
104
|
+
#
|
105
|
+
# ``` ruby
|
106
|
+
# Right.new(1).when({Right: ->x{x+1} }) # => 2
|
107
|
+
# Right.new(1).when({Left: ->x{x+1}) # => nil
|
108
|
+
# Right.new(1).when({Left: ->x{x+1}, _: ->x{x-1} }) # => 0
|
109
|
+
# ```
|
110
|
+
# @return [Either]
|
111
|
+
def when what
|
112
|
+
current_class = self.class.to_s.to_sym
|
113
|
+
if what.include? current_class
|
114
|
+
what[current_class].(@v)
|
115
|
+
elsif what.include? :_
|
116
|
+
what[:_].(@v)
|
117
|
+
end
|
118
|
+
end
|
58
119
|
|
120
|
+
# @return [String]
|
59
121
|
def inspect
|
60
122
|
case self
|
61
123
|
when Left
|
@@ -64,13 +126,58 @@ module Either
|
|
64
126
|
"#<Right value=#{@v}>"
|
65
127
|
end
|
66
128
|
end
|
129
|
+
|
130
|
+
# filter only {Right} value from List of {Either}
|
131
|
+
#
|
132
|
+
# ``` ruby
|
133
|
+
# Either.rights [Left.new(1),Right.new(5), Right.new(2)] # => [5, 2]
|
134
|
+
# ```
|
135
|
+
# @return [value]
|
136
|
+
def self.rights list_of_either
|
137
|
+
list_of_either.select(&:right?)
|
138
|
+
.map { |right| right.get_or_else(nil) }
|
139
|
+
end
|
140
|
+
|
141
|
+
# filter only {Left} value from List of {Either}
|
142
|
+
#
|
143
|
+
# ``` ruby
|
144
|
+
# Either.lefts [Left.new(1),Right.new(5), Right.new(2)] # => [1]
|
145
|
+
# ```
|
146
|
+
# @return [value]
|
147
|
+
def self.lefts list_of_either
|
148
|
+
list_of_either.select(&:left?)
|
149
|
+
.map { |left| left.when({Left: ->l{l}}) }
|
150
|
+
end
|
151
|
+
|
152
|
+
# partion a List of {Either} into a List of 2 List, one contains only {Left}, other contains only {Right}
|
153
|
+
#
|
154
|
+
# ``` ruby
|
155
|
+
# Either.partition [Left.new(1),Right.new(5), Right.new(2)] # => [[1],[5, 2]]
|
156
|
+
# ```
|
157
|
+
# @return [[l],[r]]
|
158
|
+
def self.partition list_of_either
|
159
|
+
list_of_either.inject([[],[]]) do |acc, x|
|
160
|
+
x.when({
|
161
|
+
Left: ->(l){acc[0].push(l)},
|
162
|
+
Right: ->(r){acc[1].push(r)}
|
163
|
+
})
|
164
|
+
acc
|
165
|
+
end
|
166
|
+
end
|
67
167
|
end
|
68
168
|
|
169
|
+
|
69
170
|
class Left
|
70
|
-
include Either
|
171
|
+
include Either
|
71
172
|
def initialize v=nil
|
72
173
|
@v=v
|
73
174
|
end
|
175
|
+
|
176
|
+
# always true
|
177
|
+
# @return [Boolean]
|
178
|
+
def left?
|
179
|
+
true
|
180
|
+
end
|
74
181
|
|
75
182
|
def == other
|
76
183
|
case other
|
@@ -84,6 +191,13 @@ end
|
|
84
191
|
|
85
192
|
class Right
|
86
193
|
include Either
|
194
|
+
|
195
|
+
# always true
|
196
|
+
# @return [Boolean]
|
197
|
+
def right?
|
198
|
+
true
|
199
|
+
end
|
200
|
+
|
87
201
|
def == other
|
88
202
|
case other
|
89
203
|
when Right
|
data/lib/helper.rb
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: data.either
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jichao Ouyang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-08-
|
11
|
+
date: 2016-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: The Either Monad
|
14
14
|
email: oyanglulu@gmail.com
|
@@ -16,7 +16,9 @@ executables: []
|
|
16
16
|
extensions: []
|
17
17
|
extra_rdoc_files: []
|
18
18
|
files:
|
19
|
+
- lib/control/monad.rb
|
19
20
|
- lib/data.either.rb
|
21
|
+
- lib/helper.rb
|
20
22
|
homepage: https://github.com/jcouyang/cats.rb
|
21
23
|
licenses:
|
22
24
|
- MIT
|