data.either 0.0.5 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|