mon 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,89 @@
1
+ # The List monad wraps lists. Gasp!
2
+ #
3
+ # A simple example:
4
+ # <tt>l = List[1, 2, 3]
5
+ # list9 = l.bind { |i| i * 9 } # ==> List[9, 18, 27]
6
+ # longList = l.bind { |i| [i, i * 2] } # ==> List[1, 2, 2, 4, 3, 6]</tt>
7
+ #
8
+ # Simple and straightforward.
9
+
10
+ module Mon
11
+
12
+ module Monad
13
+
14
+ require_relative 'chainable_monad'
15
+ require_relative 'monad'
16
+
17
+ class List < Monad
18
+
19
+ include ChainableMonad
20
+
21
+ def initialize(list)
22
+ @list = list
23
+ end
24
+
25
+ # Create a list. Eg: List[1, 2, 3]
26
+ def self.[](*list)
27
+ List.new(list)
28
+ end
29
+
30
+ # Apply fun to all elements of the list (ala map):
31
+ # List[1, 2, 3].map { |i| i + 5 } # ==> List[6, 7, 8]
32
+ def bind &fun
33
+ List.send(:new, @list.map { |i| fun.call(i) }.map { |i| (i.is_a? List) ? i.to_a : i}.flatten(1))
34
+ end
35
+
36
+ # Return the array wrapped by the List
37
+ def unwrap
38
+ to_a
39
+ end
40
+
41
+ # Alias for #unwrap
42
+ def _
43
+ to_a
44
+ end
45
+
46
+ def _canBind? name
47
+ @list.all? { |i| i.respond_to?(name) }
48
+ end
49
+
50
+ def to_s
51
+ (@list.length > 3) ? (tail = "...") : tail = ""
52
+ "List[#{ @list.take(3).join(", ") }#{ tail }]"
53
+ end
54
+
55
+ # Return the array wrapped by the list
56
+ def to_a
57
+ @list
58
+ end
59
+
60
+ class << self
61
+ protected :new
62
+ end
63
+
64
+ def eql?(other)
65
+ if other.is_a? List
66
+ @list == other.unwrap
67
+ elsif other.is_a? Array
68
+ @list == other
69
+ else
70
+ false
71
+ end
72
+ end
73
+
74
+ def ==(o)
75
+ eql?(o)
76
+ end
77
+
78
+ def equal?(o)
79
+ eql?(o)
80
+ end
81
+
82
+ def self::valid?(o)
83
+ o.is_a?(List)
84
+ end
85
+
86
+ protected :unwrap, :_canBind?
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,211 @@
1
+ # The Maybe monad wraps a possible value. It allows chaining of
2
+ # operations on a potentially-null value.
3
+ #
4
+ # A simple example:
5
+ # <tt>m = Maybe[callSomeIntOrNilFunction()]
6
+ # v = (m * 3 + 2).abs
7
+ # # Depending whether the original method call returned a number or nil,
8
+ # # could be either None or Some[N].</tt>
9
+
10
+ module Mon
11
+
12
+ module Monad
13
+
14
+ require_relative 'chainable_monad'
15
+ require_relative 'monad'
16
+
17
+ # Superclass for Some and None. Can be used as follows:
18
+ # <tt>m = Maybe[nil] # ==> None
19
+ # m = Maybe[5] # ==> Some[5]
20
+ # m = Maybe[nil] * 7 # ==> None
21
+ # m = Maybe[5] * 7 # ==> Some[35]
22
+ # m = Maybe[call_to_fun].someOperation(3) # ==> Some[...] or None, never an error</tt>
23
+ class Maybe < Monad
24
+ include ChainableMonad
25
+
26
+ # Override to catch None
27
+ def method_missing(name, *args, &fun)
28
+ self.bind { |o| o.send(name, *args, &fun) }
29
+ end
30
+
31
+ # Use to instantiate a Maybe monad:
32
+ # <tt>m = Maybe[<either nil/false or not>]</tt>
33
+ def self.[](obj)
34
+ if obj.is_a? Maybe
35
+ obj
36
+ elsif obj
37
+ Some[obj]
38
+ else
39
+ None[]
40
+ end
41
+ end
42
+
43
+ # Get the value, or throw an exception (using the optional supplied msg) if it's empty
44
+ def orFail(msg = nil)
45
+ msg = "#{ self } is empty!" unless msg
46
+ throw RuntimeError.new(msg)
47
+ end
48
+
49
+ # For Contracts, DEPRECATED
50
+ def valid?(o)
51
+ o.is_a? Maybe
52
+ end
53
+
54
+ class << self
55
+ protected :new
56
+ end
57
+ end
58
+
59
+ # The Some class represents a value that is NOT null/false
60
+ class Some < Maybe
61
+
62
+ def initialize(obj)
63
+ @obj = obj
64
+ super()
65
+ end
66
+
67
+ # Wrap an object. You probably want Maybe[...], but there's a slight difference:
68
+ # Maybe[nil] # ==> None
69
+ # Some[nil] # ==> Some[nil]
70
+ def self.[](obj)
71
+ if obj.is_a? None
72
+ obj
73
+ else
74
+ Some.new(obj)
75
+ end
76
+ end
77
+
78
+ # Unwrap the wrapped value, nil or not
79
+ def unwrap
80
+ @obj
81
+ end
82
+
83
+ def _canBind? name
84
+ @obj.respond_to? name
85
+ end
86
+
87
+ # If there's a wrapped value, return it. Otherwise, either return
88
+ # the supplied object, or execute the supplied block.
89
+ # Eg:
90
+ # <tt>Maybe[1].or(5) # ==> 1
91
+ # Maybe[nil].or(5) # ==> 5
92
+ # Maybe[nil].or { throw Exception.new("...") } # ==> Exception!
93
+ def or obj = nil, &f
94
+ @obj
95
+ end
96
+
97
+ # Get the value, or throw an exception (using the optional supplied msg) if it's empty
98
+ def orFail(msg = nil)
99
+ msg = "No such value!" if msg.nil?
100
+ self::or { throw RuntimeError.new(msg) }
101
+ end
102
+
103
+ # If we're wrapping a value, apply fun() to it. Otherwise, None stays None.
104
+ def bind &fun
105
+ o = fun.call(@obj)
106
+ if o.is_a? Maybe
107
+ o
108
+ elsif o
109
+ Some[o]
110
+ else
111
+ None::none
112
+ end
113
+ end
114
+
115
+ def to_s
116
+ "Some[#{ @obj.to_s }]"
117
+ end
118
+
119
+ def eql?(other)
120
+ if other.is_a? Some
121
+ @obj == other.unwrap
122
+ else
123
+ @obj == other
124
+ end
125
+ end
126
+
127
+ def ==(o)
128
+ eql?(o)
129
+ end
130
+
131
+ def equal?(o)
132
+ eql?(o)
133
+ end
134
+
135
+ class << self
136
+ protected :new
137
+ end
138
+
139
+ protected :unwrap, :_canBind?
140
+ end
141
+
142
+ class None < Maybe
143
+
144
+ # If we're wrapping a value, apply fun() to it. Otherwise, None stays None.
145
+ def bind &fun
146
+ self
147
+ end
148
+
149
+ # Unwrap the wrapped value, nil or not
150
+ def unwrap
151
+ nil
152
+ end
153
+
154
+ # If there's a wrapped value, return it. Otherwise, either return
155
+ # the supplied object, or execute the supplied block.
156
+ # Eg:
157
+ # <tt>Maybe[1].or(5) # ==> 1
158
+ # Maybe[nil].or(5) # ==> 5
159
+ # Maybe[nil].or { throw Exception.new("...") } # ==> Exception!</tt>
160
+ def or obj = nil, &f
161
+ if obj and f
162
+ f.call obj
163
+ elsif f
164
+ f.call
165
+ else
166
+ obj
167
+ end
168
+ end
169
+
170
+ def _canBind? name
171
+ true
172
+ end
173
+
174
+ # Return a new None object. Takes no args.
175
+ # <tt>None[] # ==> None</tt>
176
+ def self.[]
177
+ None.new
178
+ end
179
+
180
+ def to_s
181
+ "None"
182
+ end
183
+
184
+ def initialize
185
+ super()
186
+ end
187
+
188
+ def eql?(other)
189
+ other.is_a? None
190
+ end
191
+
192
+ def ==(o)
193
+ eql?(o)
194
+ end
195
+
196
+ def equal?(o)
197
+ eql?(o)
198
+ end
199
+
200
+ def self::none
201
+ self.new
202
+ end
203
+
204
+ class << self
205
+ protected :new
206
+ end
207
+
208
+ protected :unwrap, :_canBind?
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,11 @@
1
+
2
+ module Mon
3
+ module Monad
4
+
5
+ class Monad
6
+ # Empty class, for matching purposes
7
+ private_class_method :new
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,175 @@
1
+ # The React monad wraps a changeable value, and catches changes to that value.
2
+ #
3
+ # A simple example:
4
+ # <tt>r = React[5]
5
+ # d = r * r
6
+ # # Currently r = Reactron[5], d = Reactor[25]
7
+ # r << 25
8
+ # # Now r = Reactron[25], d = Reactor[625]
9
+ # dd = d * 2
10
+ # # d = Reactor[625], dd = Reactor[1250]</tt>
11
+ #
12
+ # More or less, this is a Listener pattern. Reactrons are listenable,
13
+ # Reactors are listeners.
14
+
15
+ module Mon
16
+
17
+ module Monad
18
+
19
+ require_relative 'chainable_monad'
20
+ require_relative 'monad'
21
+
22
+ # The React class is the parent of Reactron and Reactor. The key difference
23
+ # between the two is the presence of the << operator. The value of a Reactor is
24
+ # derived from a Reactron, and cannot be directly changed. If viewed as a tree,
25
+ # Reactrons are the root, and only the root may be changed.
26
+ #
27
+ # However, we can have more than one root!
28
+ # <tt>m = React[2] # ==> Reactron[2]
29
+ # n = React[10] # ==> Reactron[10]
30
+ # v = m * n # Currently v == Reactor[20]
31
+ # n << 5 # Now v == Reactor[10]</tt>
32
+ #
33
+ # Usage of React is straightforward:
34
+ # <tt>r = React[some_value]</tt>
35
+ class React < Monad
36
+ include ChainableMonad
37
+
38
+ # Wrap a value in a Reactron:
39
+ # <tt>r = React["test"] # ==> Reactron["test"]
40
+ def self::[] obj
41
+ if (obj.is_a? Proc)
42
+ Reactor[obj]
43
+ else
44
+ Reactron[obj]
45
+ end
46
+ end
47
+
48
+ class << self
49
+ protected :new
50
+ end
51
+
52
+ def self::valid?(v)
53
+ v.is_a? React
54
+ end
55
+ end
56
+
57
+ # The Reactron class represents a changeable value, from which other
58
+ # values can be derived (as Reactrons)
59
+ class Reactron < React
60
+
61
+ def initialize(obj)
62
+ @obj = obj
63
+ end
64
+
65
+ # You should be using React[...]
66
+ def self::[] obj
67
+ Reactron.new(obj)
68
+ end
69
+
70
+ # Apply fun to the value wrapped by this Reactron. Returns a
71
+ # Reactor. Whenever the value is changed (with <<), all derived
72
+ # Reactors are also updated.
73
+ def bind &fun
74
+ Reactor[lambda { fun.call(self.unwrap) }]
75
+ end
76
+
77
+ def _canBind? name
78
+ @obj.respond_to? name
79
+ end
80
+
81
+ # Unwrap the value contained by this Reactron
82
+ def unwrap
83
+ @obj
84
+ end
85
+
86
+ # Change the value of this Reactron
87
+ def << obj
88
+ @obj = obj
89
+ self
90
+ end
91
+
92
+ def eql? o
93
+ if o.is_a? React
94
+ @obj == o.unwrap
95
+ else
96
+ @obj == o
97
+ end
98
+ end
99
+
100
+ def equal? o
101
+ eql? o
102
+ end
103
+
104
+ def ==(o)
105
+ eql? o
106
+ end
107
+
108
+ def to_s
109
+ "Reactron[#{ @obj }]"
110
+ end
111
+
112
+ class << self
113
+ protected :new
114
+ end
115
+
116
+ protected :_canBind?
117
+ end
118
+
119
+ class Reactor < React
120
+
121
+ def initialize(fun)
122
+ @fun = fun
123
+ end
124
+
125
+ # Apply fun to the value wrapped by this Reactor (which in turn is
126
+ # a transform on some Reactron), returning another
127
+ # Reactron. Changes to the root Reactron will propagate through
128
+ # the whole tree.
129
+ def bind &fun
130
+ Reactor[lambda { fun.call(self.unwrap) }]
131
+ end
132
+
133
+ # You want React[...]
134
+ def self::[] fun
135
+ Reactor.new(fun)
136
+ end
137
+
138
+ # Unwrap the (current) value contained by this Reactor
139
+ def unwrap
140
+ r = @fun.call
141
+ r.is_a?(Reactor) ? r.unwrap : r
142
+ end
143
+
144
+ def _canBind? name
145
+ unwrap.respond_to? name
146
+ end
147
+
148
+ def eql? o
149
+ if o.is_a? React
150
+ @fun.call == o.unwrap
151
+ else
152
+ @fun.call == o
153
+ end
154
+ end
155
+
156
+ def equal? o
157
+ eql? o
158
+ end
159
+
160
+ def ==(o)
161
+ eql? o
162
+ end
163
+
164
+ def to_s
165
+ "Reactor[#{ unwrap }]"
166
+ end
167
+
168
+ class << self
169
+ protected :new
170
+ end
171
+
172
+ protected :_canBind?
173
+ end
174
+ end
175
+ end