raskell 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4795026fb8eba55958eb0ae8b7188e8e50e20cbe
4
+ data.tar.gz: c8ce90fb43aea46b81f1360bf5664e3fb164bf1b
5
+ SHA512:
6
+ metadata.gz: 58fdef50dd65ad6bb1eea500941787b1c84b6da7f61e948e43962dc92f7eb14c8352efdfc1f4ccef2783d95524b306fa887eaa802c107e815d68c36d088bbd84
7
+ data.tar.gz: 19b932ac37c062a5b94682ce5252838935e5c970a99101baf465a20a1b08dcae2bd9accb4486f2a2870d7061b431cec60fc982a0c70693f87e6afa6b4dbc7dad
@@ -0,0 +1,72 @@
1
+ # raskell
2
+ Making Ruby a Joy to Work With
3
+ =======
4
+
5
+
6
+ Usage:
7
+
8
+ Reminder: Lambdas can be applied with [\*args] notation and .() is syntactic sugar for .call()
9
+ ```f = ->(x) { x + 2 } ```
10
+ ```f[1]``` evaluates as ```3```
11
+
12
+
13
+ Lambdas can be partially applied, yielding a new lambda, with call
14
+ ```plus = ->(x,y) { x + y }```
15
+ ```plus10 = plus.(10) ## or plus[10]```
16
+ ```plus10.(20)``` evaluates as ```30```
17
+
18
+ Lambda Composition with \* (right-associative) ```( (f * g * h).(x) == f.(g.(h.(x))))```
19
+ ```times10 = ->(x) { x * 10 }```
20
+ ```minus3 = ->(x) { x - 3 }```
21
+ ```double = ->(x) { x * 2 }```
22
+
23
+ ```(times10 * minus3 * double).(5)``` evaluates as ```70```
24
+ ```(double * minus3 * times10).(5)``` evaluates as ```94```
25
+
26
+
27
+ Lambda Pipelining with \| (left-associative) ``` (f | g | h).(x) == h.(g.(f.(x))) ```
28
+ ```(times10 | minus3 | double).(5)``` evaluates as ```94```
29
+ ```(double | minus3 | times10).(5)``` evaluates as ```70```
30
+
31
+ Lambda Tupling with + (associative)
32
+ ```(times10 + minus3 + double).(5)``` evaluates as ```[50, 2, 10]```
33
+
34
+ Objects, when called, act like constant functions that throw away any values applied to them
35
+ ```5.call(1,2,3,[4,7])``` evaluates to ```5```
36
+
37
+ Arrays, when called, map across themselves calling each element with the arguments it was called with
38
+ ```[times10, minus3, double].(5)``` evaluates to ```5```
39
+ ```[plus, times10, 3].(0,1)``` evaluates to ```[1, 0, 3]```
40
+ Note that ```[plus,times10,3][0,1]``` evaluates to ```[plus]```, not ```[1, 0, 3]```, so be careful where you use ```func[]``` as shorthand ```func.()``` or ```func.call()```!
41
+
42
+ Streams, when called, map across themselves calling each element with the arguments it was called with
43
+ ```[times10, minus3, double].to_stream.(5)``` evaluates to ```5```
44
+ ```[plus, times10, 3].to_stream.(0,1)``` evaluates to ```[1, 0, 3].to_stream```
45
+ Note that ```[plus,times10,3].to_stream[0,1]``` evaluates to ```[plus].to_stream```, not ```[1, 0, 3].to_stream```, so be careful where you use ```func[]``` as shorthand ```func.()``` or ```func.call()```!
46
+
47
+ Preface any collection function with F. to call that particular function
48
+ ```F.map(times10 * plus10).([1,2,3])``` evaluates as ```[100, 200, 300]```
49
+
50
+
51
+
52
+
53
+ Available Operators to Overload in Ruby
54
+
55
+
56
+ (unary)
57
+ !, ~, +, \-
58
+
59
+ (binary)
60
+ \*\*, \*, /, %, +, \-, <<, >>, &, \|, ^, ||, &&
61
+ =, +=, \*=, -=,
62
+ <, <=, >=, >, ==, ===, !=, =~, !~, <=>
63
+ [],[]=
64
+
65
+ Using in Raskell so far
66
+ [], \*, \*\*, ^, \|, &, +, %, <<, >>
67
+
68
+ =~ and !~ will be good for later when I have 'regular expressions' over arbitrary asterated semirings - then i can match if the data, path, whatever matches a regex of allowable types - and this gives us a powerful form of type constraint for free
69
+
70
+
71
+
72
+
@@ -0,0 +1,15 @@
1
+ Making Ruby a "Joy" to Work With In X (Easy?) Steps
2
+
3
+ \*I) partial application for lambdas, treat [] as .call() for lambdas, and add .call(\*args) to objects (a no-op) and arrays (map across calling element.call(\*args) for each element)
4
+ \*II) function tupling, composition, and pipelining in the form of +,\*, and \|
5
+ \*III) a very lightweight testing framework, DoubleCheck, built using the above as a demo, along with tests for everything previously built
6
+ \*IV) a standard collections library based around fusable stream transducers - (flat)map, filter, fold\*, zip, append, scanl - Scala/Haskell eqv.
7
+ \*V) add instances of from_stream(ClassName=Array) and to_stream for Dictionary, (Multi?)Set, Array, Range, String, Integer, Object, and Enumerable
8
+ \*VI) add tupling for foldl, and (map / scanl with each other, really anything that produces as many outputs as it takes in - so might need a scanl1 and a foldl1, so we can combine any/all of them together and still succeed in only consuming a stream once) as well, so that multiple transducers can run in parallel across the same stream in a single pass
9
+ \*VII) Implement Applicative instances for Array and Stream
10
+ VIII) organize code so that it is clear what consumes the entire stream strictly (foldl-based), what consumes the entire stream lazily (scanl, everything else pretty much), and what can be combined via + to avoid multiple passes over a single stream when computing multiple functions of the stream (foldl, scanl) - example, ```(F.length + F.sum + F.product + F.sum_of_squares).([1,2,3,4].to_stream)``` computes all of those statistics in a single pass, yielding ```[4, 10, 24, 30]```, and make sure that all functions are as optimized and elegantly defined as possible. -- probably need a specialized one for very large lists, one for infinite, and one for the rest
11
+ IX) modularize for easy addition into other's projects, optimize automatically in the common cases (use array-based functions when possible instead of stream)
12
+ X) Make everything that isn't a function a 'constant' function that implicitly pushes to an ArgumentStack once lifted, and then returns the ArgumentStack. Modify lambda calling to properly use argument stack if it is passed in, and to place unused arguments onto after calling - forking lambdas - i.e. a [fn, fn2,fn3,fn4].(), duplicate argument stacks and create unique new ones in their locations, rather than 'sharing' a common argument stack - turning Raskell into a concatenative language - a "Joy" to *work* with
13
+
14
+
15
+ get rid of ^ for cartesian product, use for * instance instead
@@ -0,0 +1,11 @@
1
+ require './lib/raskell/nothing'
2
+ require './lib/raskell/identity'
3
+ require './lib/raskell/integer'
4
+ require './lib/raskell/object'
5
+ require './lib/raskell/streams'
6
+ require './lib/raskell/proc'
7
+ require './lib/raskell/array'
8
+ require './lib/raskell/folds'
9
+ require './lib/raskell/f'
10
+ require './lib/version'
11
+
@@ -0,0 +1,209 @@
1
+
2
+
3
+ class Array
4
+
5
+ def deep_clone
6
+ map(&:deep_clone)
7
+ end
8
+
9
+ def empty
10
+ []
11
+ end
12
+
13
+ def fmap(fn)
14
+ map {|x| fn.(x) }
15
+ end
16
+
17
+ def call(*args)
18
+ #functions = self.map { |x| x.kind_of?(Proc) ? self : ->() { x } }
19
+ self.any? {|x| x.kind_of? Proc } ? fmap(->(f) { f.(*args)}) : self
20
+ end
21
+
22
+ def take(n)
23
+ if n == 0
24
+ []
25
+ elsif n >= self.length
26
+ self
27
+ else
28
+ self.slice(0, n)
29
+ end
30
+ end
31
+
32
+ def drop(n)
33
+ if n == 0
34
+ self
35
+ elsif n >= self.length
36
+ []
37
+ else
38
+ self.slice(n, self.length)
39
+ end
40
+ end
41
+
42
+ def foldr(func, unit)
43
+ (self.length-1).foldr(->(idx, acc) { func.(self[idx], acc) }, unit)
44
+ end
45
+
46
+ def foldl(func, unit)
47
+ (self.length-1).foldl(->(acc, idx) { func.(acc, self[idx]) }, unit)
48
+ end
49
+
50
+ def self.next_item
51
+ next_fn = ->(state) {
52
+ i = state.first
53
+ arr = state.last
54
+ if i == arr.length
55
+ [:done]
56
+ else
57
+ [:yield, arr[i], Stream.new(next_fn, [i+1, arr])]
58
+ end
59
+ }
60
+ end
61
+
62
+ def self.to_stream(xs)
63
+ Stream.new(self.next_item, [0, xs.deep_clone])
64
+ end
65
+
66
+ def to_stream
67
+ self.class.to_stream(self)
68
+ end
69
+
70
+ alias_method :standard_equals, :==
71
+ def ==(obj)
72
+ obj.kind_of?(Stream) ? self.to_stream == obj : standard_equals(obj)
73
+ end
74
+
75
+ alias_method :standard_triple_equals, :===
76
+ def ===(obj)
77
+ obj.kind_of?(Stream) ? self.to_stream === obj : standard_triple_equals(obj)
78
+ end
79
+
80
+ end
81
+
82
+ class String
83
+
84
+ def self.empty
85
+ ""
86
+ end
87
+
88
+ def empty?
89
+ self == ""
90
+ end
91
+
92
+ def first
93
+ self[0]
94
+ end
95
+
96
+ def take(n)
97
+ if n == 0
98
+ ""
99
+ elsif n >= self.length
100
+ self
101
+ else
102
+ self.slice(0, n)
103
+ end
104
+ end
105
+
106
+ def drop(n)
107
+ if n == 0
108
+ self
109
+ elsif n >= self.length
110
+ ""
111
+ else
112
+ self.slice(n, self.length)
113
+ end
114
+ end
115
+
116
+ def self.next_item
117
+ next_fn = ->(xs) { xs.empty? ? [:done] : [:yield, xs.first, Stream.new(next_fn, xs.drop(1))] }
118
+ next_fn
119
+ end
120
+
121
+ def self.to_stream(xs)
122
+ Stream.new(self.next_item, xs)
123
+ end
124
+
125
+ def to_stream
126
+ self.class.to_stream(self)
127
+ end
128
+
129
+ alias_method :standard_equals, :==
130
+ def ==(obj)
131
+ obj.kind_of?(Stream) ? self.to_stream == obj : standard_equals(obj)
132
+ end
133
+
134
+ alias_method :standard_triple_equals, :===
135
+ def ===(obj)
136
+ obj.kind_of?(Stream) ? self.to_stream === obj : standard_triple_equals(obj)
137
+ end
138
+
139
+ end
140
+
141
+ require 'set'
142
+
143
+ class Set
144
+
145
+ def self.to_stream(set)
146
+ set.to_a.sort.to_stream
147
+ end
148
+
149
+ def to_stream
150
+ self.class.to_stream(self)
151
+ end
152
+
153
+ def push(item)
154
+ self << item
155
+ self
156
+ end
157
+
158
+ end
159
+
160
+
161
+
162
+ class Hash
163
+
164
+ def <<(keyval)
165
+ raise("Can only push pairs into a dictionary") unless (keyval.kind_of?(Array) || keyval.kind_of?(Stream))
166
+ self[keyval.first]=keyval.last
167
+ self
168
+ end
169
+
170
+ def push(pair)
171
+ self <<(pair)
172
+ self
173
+ end
174
+
175
+ def to_stream
176
+ ## have to sort to ensure stream == works
177
+ self.class.to_stream(self)
178
+ end
179
+
180
+ def self.to_stream(xs)
181
+ ## have to sort to ensure steream == works
182
+ xs.to_a.sort {|x,y| x.first <=> y.first}.to_stream
183
+ end
184
+
185
+ alias_method :standard_equals, :==
186
+ def ==(obj)
187
+ obj.kind_of?(Stream) ? self.sort.to_stream == obj : standard_equals(obj)
188
+ end
189
+
190
+ alias_method :standard_triple_equals, :===
191
+ def ===(obj)
192
+ obj.kind_of?(Stream) ? self.to_stream === obj : standard_triple_equals(obj)
193
+ end
194
+
195
+ def deep_clone
196
+ Hash.new(self.map{|k,v| [k.deep_clone, v.deep_clone]})
197
+ end
198
+
199
+ end
200
+
201
+ # class Range
202
+ # def to_stream
203
+ # F.range(self.min, self.max)
204
+ # end
205
+
206
+ # def self.to_stream(range)
207
+ # F.range.(range.min, range.max)
208
+ # end
209
+ # end
@@ -0,0 +1,1448 @@
1
+
2
+ ## module System
3
+ class F ## @@System||=:F to use 3;) --- or, you can just extend with System, and get the F for free.
4
+ # stream combinators
5
+ @@to_stream = ->(xs) { xs.to_stream }
6
+
7
+ def self.to_stream
8
+ @@to_stream
9
+ end
10
+
11
+ def self.from_stream(*args)
12
+ if args.length > 0
13
+ FromStream.new().(*args)
14
+ else
15
+ FromStream.new()
16
+ end
17
+ end
18
+
19
+ def self.to_array
20
+ FromStream.new(Array)
21
+ end
22
+
23
+ def self.to_hash
24
+ FromStream.new(Hash)
25
+ end
26
+
27
+ def self.to_set
28
+ FromStream.new(Set)
29
+ end
30
+
31
+ def self.to_a
32
+ self.to_array
33
+ end
34
+
35
+ def self.to_h
36
+ self.to_hash
37
+ end
38
+
39
+ def self.infinity
40
+ Float::INFINITY
41
+ end
42
+
43
+ def self.negative_infinity
44
+ -Float::INFINITY
45
+ end
46
+
47
+ def self.inf
48
+ Float::INFINITY
49
+ end
50
+
51
+ def self.ninf
52
+ -Float::INFINITY
53
+ end
54
+
55
+ def self.id
56
+ Identity.new # ->(x) { x }
57
+ end
58
+
59
+ def self.apply_with2
60
+ @@apply_with2||= ->(y, f, x) { f.(x,y)}
61
+ end
62
+
63
+ def self.apply
64
+ @@apply||= ->(f, *xs) { f.(*xs) }
65
+ end
66
+
67
+ def self.apply_with
68
+ @@apply_with||= ->(x,f) { f.(x) } # flip * apply
69
+ end
70
+
71
+ def self.compose
72
+ @@compose||= ->(f,g) { f * g }
73
+ end
74
+
75
+ def self.flip
76
+ @@flip||= -> (f,x,y) { f.(y,x) }
77
+ end
78
+
79
+ def self.slf
80
+ @@slf||= -> (f, x) { f.(x,x) } ## square = slf * times
81
+ end
82
+
83
+ def self.fix
84
+ @@fix||= ->(f, x) {
85
+ result = x
86
+ next_result = f.(x)
87
+ while result != next_result
88
+ result = next_result
89
+ next_result = f.(result)
90
+ end
91
+ result
92
+ }
93
+ end
94
+
95
+ ## next_stream_fn yields Nothing for stop, and the next stream to go to otherwise
96
+ ## yield_fn yields a Nothing for skip, and the next value to yield otherwise
97
+ def self.cstep
98
+ @@cstep||= ->(next_stream_fn, yield_fn) {
99
+ ## next_stream_fn :: state -> next_fn -> Maybe(stream)
100
+ ## yield_fn :: state -> Maybe(item)
101
+ next_fn = ->(state) {
102
+ next_stream = next_stream_fn.(state)
103
+ to_yield = yield_fn.(state) if to_skip != Nothing
104
+ if next_stream == Nothing
105
+ [:done]
106
+ elsif to_yield == Nothing
107
+ [:skip, next_stream]
108
+ else
109
+ [:yield, to_yield, next_stream]
110
+ end
111
+ }
112
+ next_fn
113
+ }
114
+ end
115
+
116
+ def self.step
117
+ @@step||= ->(transition_fn, yield_fn) {
118
+ ## transition_fn :: state -> Maybe(state)
119
+ ## yield_fn :: state -> Maybe(item)
120
+ next_fn = ->(state) {
121
+ next_state = transition_fn.(state)
122
+ to_yield = yield_fn.(state) if next_state != Nothing
123
+ if next_state == Nothing
124
+ [:done]
125
+ elsif to_yield == Nothing
126
+ [:skip, Stream.new(next_fn, next_state)]
127
+ else
128
+ [:yield, to_yield, Stream.new(next_fn, next_state)]
129
+ end
130
+ }
131
+ next_fn
132
+ }
133
+ end
134
+
135
+ ## booleans
136
+ def self.not
137
+ @@not||= ->(x) { !x }
138
+ end
139
+
140
+ def self.and
141
+ @@and||= ->(x,y) { x && y }
142
+ end
143
+
144
+ def self.nand
145
+ @@nand||= ->(x,y) { !(x && y) }
146
+ end
147
+
148
+ def self.or
149
+ @@or||= ->(x,y) { x || y }
150
+ end
151
+
152
+ def self.nor
153
+ @@nor||= ->(x,y) { !x && !y }
154
+ end
155
+
156
+ def self.xor
157
+ @@xor||= ->(x,y) { !(x && y) && (x || y) }
158
+ end
159
+
160
+ ## numbers
161
+ def self.inc
162
+ @@inc||= ->(x) { x + 1 }
163
+ end
164
+
165
+ def self.dec
166
+ @@dec||= ->(x) { x - 1 }
167
+ end
168
+
169
+ def self.plus
170
+ @@plus||= ->(x,y) { x + y }
171
+ end
172
+
173
+ def self.times
174
+ @@times||= ->(x,y) { x * y }
175
+ end
176
+
177
+ def self.sub_from
178
+ @@sub_from||= ->(x,y) { x - y }
179
+ end
180
+
181
+ def self.div_from
182
+ @@div_from||= ->(x,y) { x / y }
183
+ end
184
+
185
+ def self.div_by
186
+ @@div_by||= ->(y,x) { x / y}
187
+ end
188
+
189
+ def self.sub_by
190
+ @@sub_by||= ->(y,x) { x - y}
191
+ end
192
+
193
+ def self.equals
194
+ @@equals||= ->(x,y) { x == y }
195
+ end
196
+
197
+ def self.equal
198
+ @@equal||= ->(x,y) { x == y }
199
+ end
200
+
201
+ def self.eq
202
+ @@eq||= ->(x,y) { x === y }
203
+ end
204
+
205
+ def self.is_gt
206
+ @@is_gt||= ->(y,x) { x > y }
207
+ end
208
+
209
+ def self.is_lt
210
+ @@is_lt||= ->(y,x) { x < y }
211
+ end
212
+
213
+ def self.is_gte
214
+ @@is_gte||= ->(y,x) { x >= y }
215
+ end
216
+
217
+ def self.is_lte
218
+ @@is_lte||= ->(y,x) { x <= y }
219
+ end
220
+
221
+ def self.gt
222
+ @@gt||= ->(x,y) { x > y }
223
+ end
224
+
225
+ def self.lt
226
+ @@lt||= ->(x,y) { x < y }
227
+ end
228
+
229
+ def self.gte
230
+ @@gte||= ->(x,y) { x >= y }
231
+ end
232
+
233
+ def self.lte
234
+ @@lte||= ->(x,y) { x <= y }
235
+ end
236
+
237
+ #insert ln, lg, log, log_base, e, pi, exp/pow, square, cube, nth_root, sqrt here later
238
+ def self.max
239
+ @@max||= ->(x,y) { x >= y ? x : y}
240
+ end
241
+
242
+ def self.min
243
+ @@min||= ->(x,y) { x <= y ? x : y}
244
+ end
245
+
246
+ ## streams
247
+ def self.empty
248
+ @@empty||= Stream.new(->(x) { [:done] }, Nothing)
249
+ end
250
+
251
+ def self.wrap
252
+ @@wrap||= ->(x) {
253
+ next_fn = ->(bool) { bool ? [:yield, x, Stream.new(next_fn, false)] : [:done]}
254
+ Stream.new(next_fn, true)
255
+ }
256
+ end
257
+
258
+ def self.cons
259
+ @@cons||= ->(el) {
260
+ ->(stream) {
261
+ Stream.new(->(x) { [:yield, el, stream] } , Nothing)
262
+ } * to_stream
263
+ }
264
+ end
265
+
266
+
267
+ def self.first
268
+ @@first||= -> (stream) { ## should offer an equivalent that returns a stream with a single element
269
+ next_item = stream.next_item
270
+ while next_item.first == :skip
271
+ next_item = next_item.last.next_item
272
+ end
273
+ next_item.first == :yield ? next_item[1] : Nothing
274
+ } * to_stream
275
+ end
276
+
277
+ def self.rest
278
+ @@rest||= -> (stream) {
279
+ next_item = stream.next_item
280
+ next_item == [:done] ? Nothing : next_item.last
281
+ } * to_stream
282
+ end
283
+
284
+ def self.take
285
+ @@take||= ->(n) {
286
+ raise("#{n} must be a positive number") if n < 0
287
+ ->(stream) {
288
+ next_fn = step.(->(state){
289
+ if state.first == 0
290
+ Nothing
291
+ else
292
+ next_item = state.last.next_item
293
+ count = next_item.first == :skip ? state.first : state.first-1
294
+ next_item == [:done] ? Nothing : [count, next_item.last]
295
+ end
296
+ },
297
+ ->(state) {
298
+ next_item = state.last.next_item
299
+ next_item.first == :yield ? next_item[1] : Nothing
300
+ })
301
+ Stream.new(next_fn, [n, stream])
302
+ } * to_stream
303
+ }
304
+ end
305
+
306
+ def self.drop
307
+ @@drop||= ->(n) {
308
+ raise("#{n} must be a positive number") if n < 0
309
+ ->(stream) {
310
+ next_fn = step.(->(state){
311
+ next_item = state.last.next_item
312
+ count = next_item.first == :skip || state.first == 0 ? state.first : state.first-1
313
+ next_item == [:done] ? Nothing : [count, next_item.last]
314
+ },
315
+ ->(state) {
316
+ count = state.first
317
+ next_item = state.last.next_item
318
+ next_item.first == :yield && count == 0 ? next_item[1] : Nothing
319
+ })
320
+ Stream.new(next_fn, [n, stream])
321
+ } * to_stream
322
+ }
323
+ end
324
+
325
+ def self.drop_except
326
+ @@drop_except||= ->(n) {
327
+ raise("#{n} must be a positive number") if n < 0
328
+ ->(stream) {
329
+ next_fn = ->(strm) {
330
+ potential_stream = take.(n+1) << strm
331
+ if (length.(potential_stream)) < n+1
332
+ [:skip, take.(n) << strm]
333
+ else
334
+ next_item = strm.next_item
335
+ tag = next_item.first
336
+ val = next_item[1]
337
+ next_strm = next_item.last
338
+ if tag == :done
339
+ [:done]
340
+ elsif tag == :skip
341
+ [:skip, next_strm]
342
+ elsif tag == :yield
343
+ [:skip, next_strm]
344
+ else
345
+ raise "#{next_item} is a malformed stream response!"
346
+ end
347
+ end
348
+ }
349
+ Stream.new(next_fn, stream)
350
+ } * to_stream
351
+ }
352
+ end
353
+
354
+ def self.init
355
+ @@init||= ->(stream) {
356
+ next_fn = ->(state) {
357
+ strm = state.last
358
+ next_item = strm.next_item
359
+ if next_item == [:done] && state.first == Nothing
360
+ raise "init requires a stream length of at least 1"
361
+ elsif next_item == [:done]
362
+ [:done]
363
+ elsif next_item.first == :skip
364
+ [:skip, Stream.new(next_fn, [state.first, next_item.last])]
365
+ elsif next_item.first == :yield && state.first == Nothing
366
+ [:skip, Stream.new(next_fn, [next_item[1], next_item.last])]
367
+ elsif next_item.first == :yield
368
+ [:yield, state.first, Stream.new(next_fn, [next_item[1], next_item.last])]
369
+ else
370
+ raise "#{next_item} is a malformed stream response"
371
+ end
372
+ }
373
+ Stream.new(next_fn, [Nothing, stream])
374
+ } * to_stream
375
+ end
376
+
377
+ def self.take_while
378
+ @@take_while||= ->(fn) {
379
+ raise("take_while requires a function") unless fn.kind_of?(Proc)
380
+ ->(stream) {
381
+ next_fn = ->(state) {
382
+ next_item = state.next_item
383
+ tag = next_item.first
384
+ val = next_item[1]
385
+ next_stream = next_item.last
386
+ if tag == :done || (tag == :yield && !fn.(val))
387
+ [:done]
388
+ elsif tag == :skip
389
+ [:skip, Stream.new(next_fn, next_stream)]
390
+ elsif tag == :yield
391
+ [:yield, val, Stream.new(next_fn, next_stream)]
392
+ else
393
+ raise("#{next_item} is a malformed stream response!")
394
+ end
395
+ }
396
+ Stream.new(next_fn, stream)
397
+ } * to_stream
398
+ }
399
+ end
400
+
401
+ def self.drop_while
402
+ @@drop_while||= ->(fn) {
403
+ raise("drop_while requires a function") unless fn.kind_of?(Proc)
404
+ ->(stream) {
405
+ next_fn = ->(state) {
406
+ next_item = state.next_item
407
+ tag = next_item.first
408
+ val = next_item[1]
409
+ next_strm = next_item.last
410
+ if tag == :done
411
+ [:done]
412
+ elsif tag == :skip || (tag == :yield && fn.(val))
413
+ [:skip, Stream.new(next_fn, next_strm)]
414
+ elsif tag == :yield
415
+ [:yield, val, next_strm]
416
+ else
417
+ raise("#{next_item} is a malformed stream response!")
418
+ end
419
+ }
420
+ Stream.new(next_fn, stream)
421
+ } * to_stream
422
+ }
423
+ end
424
+
425
+ def self.take_until
426
+ @@take_until||= ->(fn) {
427
+ raise("take_while requires a function") unless fn.kind_of?(Proc)
428
+ ->(stream) {
429
+ next_fn = ->(state) {
430
+ next_item = state.next_item
431
+ tag = next_item.first
432
+ val = next_item[1]
433
+ next_stream = next_item.last
434
+ if tag == :done || (tag == :yield && fn.(val))
435
+ [:done]
436
+ elsif tag == :skip
437
+ [:skip, Stream.new(next_fn, next_stream)]
438
+ elsif tag == :yield
439
+ [:yield, val, Stream.new(next_fn, next_stream)]
440
+ else
441
+ raise("#{next_item} is a malformed stream response!")
442
+ end
443
+ }
444
+ Stream.new(next_fn, stream)
445
+ } * to_stream
446
+ }
447
+ end
448
+
449
+ def self.drop_until
450
+ @@drop_until||= ->(fn) {
451
+ raise("drop_while requires a function") unless fn.kind_of?(Proc)
452
+ ->(stream) {
453
+ next_fn = ->(state) {
454
+ next_item = state.next_item
455
+ tag = next_item.first
456
+ val = next_item[1]
457
+ next_strm = next_item.last
458
+ if tag == :done
459
+ [:done]
460
+ elsif tag == :skip || (tag == :yield && !fn.(val))
461
+ [:skip, Stream.new(next_fn, next_strm)]
462
+ elsif tag == :yield
463
+ [:yield, val, next_strm]
464
+ else
465
+ raise("#{next_item} is a malformed stream response!")
466
+ end
467
+ }
468
+ Stream.new(next_fn, stream)
469
+ } * to_stream
470
+ }
471
+ end
472
+
473
+ def self.zip_with
474
+ @@zip_with||= ->(fn) {
475
+ ->(left_stream, right_stream, *streams) {
476
+ streams = ([left_stream, right_stream] + streams).map(&:to_stream)
477
+ next_fn = ->(state) {
478
+ val_so_far = state.first
479
+ strms = state.drop(1)
480
+ next_stream = strms.first
481
+ next_item = next_stream.next_item
482
+ new_streams = strms.drop(1) + [next_stream.next_item.last == :done ? empty : next_item.last]
483
+ tag = next_item.first
484
+ val = tag == :done ? nil : next_item[1]
485
+ if tag == :done
486
+ [:done]
487
+ elsif tag == :skip
488
+ [:skip, Stream.new(next_fn, [val_so_far] + new_streams)]
489
+ elsif tag == :yield && val_so_far.length == streams.length - 1
490
+ [:yield, fn.(*(val_so_far + [val])), Stream.new(next_fn, [[]] + new_streams)]
491
+ elsif tag == :yield
492
+ [:skip, Stream.new(next_fn, [val_so_far + [val]] + new_streams)]
493
+ else
494
+ raise "#{next_item} is a malformed stream response!"
495
+ end
496
+ }
497
+
498
+ Stream.new(next_fn, [[]] + streams)
499
+ }
500
+ }
501
+ end
502
+
503
+ ## lists
504
+ def self.list
505
+ @@list||= ->(*items) { items }
506
+ end
507
+
508
+ def self.empty?
509
+ @@empty_p||= F.equal.(empty)
510
+ end
511
+
512
+ def self.null?
513
+ @@null_p||= F.equal.(empty)
514
+ end
515
+
516
+ def self.double
517
+ @@double||= slf.(plus)
518
+ end
519
+
520
+ def self.square
521
+ @@square||= slf.(times)
522
+ end
523
+
524
+ def self.app
525
+ @@app||= ->(*fs) { apply.(fs.first, fs.drop(1)) }
526
+ end
527
+
528
+ def self.snoc
529
+ @@snoc||= ->(el) {
530
+
531
+ ->(stream) {
532
+ # next_fn = step.(->(stream) {
533
+ # next_item = stream.next_item
534
+ # next_item == [:done] ? wrap.(el) : next_item.last
535
+ # },
536
+ # ->(stream) {
537
+ # next_item = stream.next_item
538
+ # next_item.first == :skip ? Nothing : next_item[1]
539
+ # })
540
+ next_fn = ->(s) {
541
+ next_item = s.next_item
542
+ if next_item == [:done]
543
+ [:skip, wrap.(el)]
544
+ elsif next_item.first == :skip
545
+ [:skip, Stream.new(next_fn, next_item.last)]
546
+ elsif next_item.first == :yield
547
+ [:yield, next_item[1], Stream.new(next_fn, next_item.last)]
548
+ else
549
+ raise "#{next_item} is a malformed stream result"
550
+ end
551
+ }
552
+ Stream.new(next_fn, stream)
553
+ } * to_stream
554
+ }
555
+ end
556
+
557
+ def self.zip
558
+ @@zip||= zip_with.(list)
559
+ end
560
+
561
+ def self.unfoldl
562
+ @@unfoldl||= -> (next_fn, stop_fn, seed) {
563
+ stream_next_fn = ->x { x }
564
+ Stream.new(stream_next_fn, seed)
565
+ }
566
+ end
567
+
568
+
569
+ def self.transducer
570
+ @@transducer||= ->(next_val_fn, next_state_fn, stop_fn) {
571
+ ->(stream) {
572
+ next_fn = ->(state) {
573
+ if stop_fn.(state)
574
+ [:done]
575
+ elsif (next_val = next_val_fn.(state)) == Nothing
576
+ [:skip, next_state_fn.(state)]
577
+ else
578
+ [:yield, next_val_fn.(state), next_state_fn.(state)]
579
+ end
580
+ }
581
+ Stream.new(next_fn, stream)
582
+ } * to_stream
583
+ }
584
+ end
585
+
586
+ def self.mapleft
587
+ @@mapleft||= ->(fn) {
588
+ ->(stream) {
589
+ next_fn = ->(state) {
590
+ next_el = state.next_item
591
+ if next_el == [:done]
592
+ [:done]
593
+ elsif next_el.first == :skip
594
+ [:skip, Stream.new(next_fn, next_el.last)]
595
+ elsif next_el.first == :yield
596
+ [:yield, fn.(next_el[1]), Stream.new(next_fn, next_el.last)]
597
+ else
598
+ raise "#{next_el.inspect} is not a valid stream state!"
599
+ end
600
+ }
601
+ Stream.new(next_fn, stream)
602
+ } * to_stream
603
+ }
604
+ end
605
+
606
+ def self.foldleft
607
+ @@foldleft||= ->(f,u) {
608
+
609
+ ->(stream) {
610
+ next_item = stream.next_item
611
+ result = u
612
+ while next_item != [:done]
613
+ if next_item.first == :skip
614
+
615
+ elsif next_item.first == :yield
616
+ result = f.(result, next_item[1])
617
+ else
618
+ raise "#{next_item} is a malformed stream response"
619
+ end
620
+ next_item = next_item.last.next_item
621
+ end
622
+ result
623
+ } * to_stream
624
+
625
+ }
626
+ end
627
+
628
+ def self.scanleft
629
+ @@scanleft||= ->(f,u) {
630
+ ->(stream) {
631
+ next_fn = ->(state) {
632
+ result_so_far = state.first
633
+ strm = state.last
634
+ next_item = strm.next_item
635
+ tag = next_item[0]
636
+ val = next_item[1]
637
+ next_stream = next_item.last
638
+ if tag == :done
639
+ [:done]
640
+ elsif tag == :skip
641
+ [:skip, Stream.new(next_fn, [result_so_far, next_stream])]
642
+ elsif tag == :yield
643
+ new_result = f.(result_so_far, val)
644
+ [:yield, new_result, Stream.new(next_fn, [new_result, next_stream]) ]
645
+ else
646
+ raise "#{next_item} is a malformed stream response"
647
+ end
648
+ }
649
+ Stream.new(next_fn, [u, stream])
650
+ } * to_stream
651
+
652
+ }
653
+ end
654
+
655
+ def self.zip_with_index
656
+ @@zip_with_index||= F.zip_with.(F.list).(F.range.(0, F.infinity))
657
+ end
658
+
659
+ def self.apply_fn
660
+ @@apply_fn||= -> (f, *args) { f.(*args)}
661
+ end
662
+
663
+ ## functional combinators - higher-order functions generic over their container
664
+
665
+ ## implement this and foldl instead as first implementing scanl and scanr, and then choosing the very last value of the stream
666
+ ## so that we can have an abort-fold-when that gives the value collected so far like a loop that terminates early
667
+ def self.foldr
668
+ @@foldr||= ->(f,u) {
669
+ ->(stream) {
670
+ next_item = stream.next_item
671
+ if next_item == [:done]
672
+ u
673
+ elsif next_item.first == :skip
674
+ foldr.(f, u, next_item.last)
675
+ elsif next_item.first == :yield
676
+ f.(next_item[1], foldr.(f, u, next_item.last))
677
+ else
678
+ raise "#{next_item} is improperly formed for a Stream"
679
+ end
680
+ } * to_stream
681
+
682
+ }
683
+ end
684
+
685
+ def self.filter
686
+ @@filter||= ->(fn) {
687
+ ->(stream) {
688
+ next_fn = ->(state) {
689
+ next_el = state.next_item
690
+ if next_el == [:done]
691
+ [:done]
692
+ elsif next_el.first == :skip || (next_el.first == :yield && !fn.(next_el[1]))
693
+ [:skip, Stream.new(next_fn, next_el.last)]
694
+ elsif next_el.first == :yield && fn.(next_el[1])
695
+ [next_el.first, next_el[1], Stream.new(next_fn, next_el.last)]
696
+ else
697
+ raise "#{next_el.inspect} is not a valid stream state!"
698
+ end
699
+ }
700
+ Stream.new(next_fn, stream)
701
+ } * to_stream
702
+ }
703
+ end
704
+
705
+ def self.flatmap
706
+ @@flatmap||= ->(fn) {
707
+
708
+ ->(stream) {
709
+ next_fn = ->(next_el) {
710
+ state = next_el.first
711
+ potential_stream = next_el.last
712
+ if potential_stream == Nothing
713
+ next_el = state.next_item
714
+ if next_el == [:done]
715
+ [:done]
716
+ elsif next_el.first == :skip
717
+ [:skip, Stream.new(next_fn, [next_el.last, Nothing])]
718
+ elsif next_el.first == :yield
719
+ [:skip, Stream.new(next_fn, [next_el.last, fn.(next_el[1])])]
720
+ else
721
+ raise "#{next_el.inspect} is not a valid stream state!"
722
+ end
723
+ else
724
+ next_el = potential_stream.next_item
725
+ if next_el == [:done]
726
+ [:skip, Stream.new(next_fn, [state, Nothing])]
727
+ elsif next_el.first == :skip
728
+ [:skip, Stream.new(next_fn, [state, next_el.last])]
729
+ elsif next_el.first == :yield
730
+ [:yield, next_el[1], Stream.new(next_fn, [state, next_el.last])]
731
+ else
732
+ raise "#{next_el.inspect} is not a valid stream state!"
733
+ end
734
+ end
735
+ }
736
+ Stream.new(next_fn, [stream, Nothing])
737
+ } * to_stream
738
+
739
+ }
740
+ end
741
+
742
+ def self.range
743
+ @@range||= ->(begin_with, end_with) {
744
+ (if begin_with <= end_with
745
+ stream_next_fn = ->(n) { n > end_with ? [:done] : [:yield, n, Stream.new(stream_next_fn, n + 1)] }
746
+ Stream.new(stream_next_fn, begin_with)
747
+ else
748
+ stream_next_fn = ->(n) { n < end_with ? [:done] : [:yield, n, Stream.new(stream_next_fn, n - 1)] }
749
+ Stream.new(stream_next_fn, begin_with)
750
+ end)
751
+ }
752
+ end
753
+
754
+ def self.append
755
+ @@append||= ->(left_stream) {
756
+ ->(right_stream) {
757
+ left_next_fn = ->(stream) {
758
+ next_el = stream.next_item
759
+ if next_el == [:done]
760
+ [:skip, right_stream]
761
+ elsif next_el.first == :skip
762
+ [:skip, Stream.new(left_next_fn, next_el.last)]
763
+ elsif next_el.first == :yield
764
+ [next_el.first, next_el[1], Stream.new(left_next_fn, next_el.last)]
765
+ else
766
+ raise "#{next_el.inspect} is not a valid stream state!"
767
+ end
768
+ }
769
+
770
+ Stream.new(left_next_fn, left_stream)
771
+ } * to_stream
772
+
773
+ } * to_stream
774
+ end
775
+
776
+ def self.initial
777
+ @@initial||= ->(stream) {
778
+ next_fn = ->(strm) {
779
+ next_item = strm.next_item
780
+ if next_item.first == :done
781
+ raise "Must have at least one item inside of the stream!"
782
+ elsif next_item.first == :yield
783
+ [:yield, next_item[1], empty]
784
+ elsif next_item.first == :skip
785
+ [:skip, next_item.last]
786
+ else
787
+ raise("#{next_item} is a malformed stream response!")
788
+ end
789
+ }
790
+ Stream.new(next_fn, stream)
791
+ }
792
+ end
793
+
794
+ def self.final
795
+ @@final||= -> (stream) {
796
+ next_fn = ->(state) {
797
+ prev_step = state.first
798
+ strm = state.last
799
+ raise("Must have at least one item inside of the stream!") if prev_step == [:done]
800
+ next_item = strm.next_item
801
+ if prev_step.first == :skip
802
+ [:skip, Stream.new(next_fn, [next_item, next_item.last])]
803
+ elsif next_item == [:done]
804
+ [:yield, prev_step[1], empty]
805
+ elsif next_item.first == :yield
806
+ [:skip, Stream.new(next_fn, [next_item, next_item.last])]
807
+ elsif next_item.first == :skip
808
+ [:skip, Stream.new(next_fn, [prev_step, next_item.last])]
809
+ else
810
+ raise "#{next_item} is a malformed stream result"
811
+ end
812
+ }
813
+ next_item = stream.next_item
814
+ Stream.new(next_fn, [next_item, next_item.last])
815
+ } * to_stream
816
+ end
817
+
818
+
819
+
820
+ def self.suffixes
821
+ @@suffixes||= ->(stream) {
822
+ next_fn = ->(strm) {
823
+ next_item = strm.next_item
824
+ if next_item.first == :done
825
+ [:yield, strm, empty]
826
+ elsif next_item.first == :yield
827
+ [:yield, strm, Stream.new(next_fn, next_item.last)]
828
+ elsif next_item.first == :skip
829
+ [:skip, Stream.new(next_fn, next_item.last)]
830
+ else
831
+ raise("#{next_item} is a malformed stream response!")
832
+ end
833
+ }
834
+ Stream.new(next_fn, stream)
835
+ } * to_stream
836
+ end
837
+
838
+
839
+ def self.prefixes
840
+ @@prefixes||= foldr.(->(el, acc) { cons.(empty, map.(cons.(el), acc)) }, wrap.(empty))
841
+ end
842
+
843
+ def self.naturals
844
+ @@naturals||= range.(1, infinity)
845
+ end
846
+
847
+ ## stream functions
848
+ def self.last
849
+ @@last||= first * final
850
+ end
851
+
852
+ def self.uncons
853
+ @@uncons||= ->(s) { append(first.(l), wrap(rest.(l))) } * to_stream
854
+ end
855
+
856
+ def self.unsnoc
857
+ @@unsnoc||= ->(s) { append(wrap(init.(s)), last.(s)) } * to_stream
858
+ end
859
+
860
+ def self.reverse
861
+ @@reverse||= foldl.(->(acc, el) { cons.(el, acc) }, []) ## or foldr.(->(el,acc) { snoc.(acc, el) }
862
+ end
863
+
864
+ def self.length
865
+ @@length||= foldl.(inc, 0)
866
+ end
867
+
868
+ def self.length_at_least
869
+ @@length_at_least||= ->(n) { ->(x) { x != Nothing } * find_where.(equals.(n)) * scanl.(inc, 0) }
870
+ end
871
+
872
+ def self.concat
873
+ @@concat||= flatmap.(to_stream)
874
+ end
875
+
876
+ def self.enconcat
877
+ @@enconcat||= ->(left_stream, el) { append.(left_stream.to_stream) * cons.(el) * to_stream }
878
+ end
879
+
880
+ def self.replace
881
+ @@replace||= ->(to_replace, to_replace_with) {map.(->(x) { x == to_replace ? to_replace_with : x })}
882
+ end
883
+
884
+ def self.replace_with
885
+ @@replace_with||= ->(to_replace_with, to_replace) { map.(->(x) { x == to_replace ? to_replace_with : x }) }
886
+ end
887
+
888
+ def self.find_where
889
+ @@find_where||= ->(fn){ first * filter.(fn) }
890
+ end
891
+
892
+ def self.find_last_where
893
+ @@find_last_where||= ->(fn){ last * filter.(fn) }
894
+ end
895
+
896
+ def self.transpose
897
+ @@transpose||= ->(stream_of_streams) { zip.( *(stream_of_streams.to_stream) ) }
898
+ end
899
+
900
+ def self.tail
901
+ @@tail||= rest
902
+ end
903
+
904
+ def self.prefix
905
+ @@prefix||= init
906
+ end
907
+
908
+ def self.suffix
909
+ @@suffix||= rest
910
+ end
911
+
912
+ def self.head
913
+ @@head||= first
914
+ end
915
+
916
+ def self.inits
917
+ @@inits||= prefixes
918
+ end
919
+
920
+ def self.tails
921
+ @@tails||= suffixes
922
+ end
923
+
924
+ def self.starts_with
925
+ @@starts_with||= ->(slice, xs) { }
926
+ end
927
+
928
+ def self.ends_with
929
+ @@ends_with||= ->(slice, xs) { }
930
+ end
931
+
932
+ def self.intersperse
933
+ @@intersperse||= ->(x, xs) { rest * flatmap.(->(y) { [x, y] }) << xs.to_stream }
934
+ end
935
+
936
+ # stream folds useful for containers of numbers (core statistics algorithms)
937
+
938
+ def self.maximum
939
+ @@maximum||= foldl.(max, negative_infinity)
940
+ end
941
+
942
+ def self.minimum
943
+ @@minimum||= foldl.(min, infinity)
944
+ end
945
+
946
+ def self.maximum_by
947
+ @@maximum_by||= ->(fn) { foldl.(->(max_so_far, el) { max_so_far == Nothing || fn.(el) > fn.(max_so_far) ? el : max_so_far}, Nothing) }
948
+ end
949
+
950
+ def self.minimum_by
951
+ @@minimum_by||= ->(fn) { foldl.(->(min_so_far, el) { min_so_far == Nothing || fn.(el) < fn.(min_so_far) ? el : min_so_far}, Nothing) }
952
+ end
953
+
954
+ def self.sum
955
+ @@sum||= foldl.(plus, 0)
956
+ end
957
+
958
+ def self.product
959
+ @@product||= foldl.(times, 1)
960
+ end
961
+
962
+ ## this is a one-pass algorithm, but only an estimate
963
+ #sum_of_squares_of_differences_from_mean_iterative
964
+ ## - need length, sum, sum_of_squares, M1,M2,M3, deltas, etc... see @@https||=//en.wikipedia.org/wiki/Algorithms_for_calculating_variance
965
+ ## population_variance
966
+ ## sample_variance
967
+ #->(l) {
968
+ # len, sm, sm_sqrs = (length + sum + sum_of_squares).(l)
969
+ #}
970
+
971
+
972
+ def self.repeat
973
+ @@repeat||= ->(n, fn, x) {
974
+ result = x
975
+ count = n
976
+ while count > 0
977
+ result = fn.(result)
978
+ end
979
+ result
980
+ }
981
+ end
982
+
983
+ def self.rotate
984
+ @@rotate||= ->(s) { append.(tail.(s), initial.(s)) }
985
+ end
986
+
987
+ def self.first_index_where
988
+ @@first_index_where||= ->(fn) { first * find_where.( fn * last ) * zip_with_index }
989
+ end
990
+
991
+ def self.last_index_where
992
+ @@last_index_where||= ->(fn) { first * last * filter.( fn * last ) * zip_with_index }
993
+ end
994
+
995
+ def self.mean
996
+ @@mean||= ->(l) { div_from.(*( (sum + length).(l) )) }
997
+ end ## this works because (sum + length).(l)== [sum.(l), length.(l)]
998
+
999
+ def self.sum_of_squares
1000
+ @@sum_of_squares||= sum * map.(square)
1001
+ end
1002
+
1003
+ ## this is a two-pass algorithm
1004
+
1005
+ def self.sum_of_differences_from_estimated_mean
1006
+ @@sum_of_differences_from_estimated_mean||= ->(xs) {
1007
+ sum * map.(square * sub_by.())
1008
+ }
1009
+ end
1010
+
1011
+ # stream folds useful for containers of booleans
1012
+ def self.ands
1013
+ @@ands||= ->(x) { x == Nothing } * find_where.(F.equals.(false))
1014
+ end
1015
+
1016
+ def self.ors
1017
+ @@ors||= ->(x) { x != Nothing } * find_where.(F.equals.(true))
1018
+ end
1019
+
1020
+
1021
+ ## stream functionals
1022
+ def self.contains?
1023
+ @@contains_p||= ->(el) { F.not * F.equal.(Nothing) * find_where.(equals.(el)) }
1024
+ end
1025
+
1026
+ def self.does_not_contain?
1027
+ @@does_not_contain_p||= ->(el) { F.equal.(Nothing) * find_where.(equals.(el)) }
1028
+ end
1029
+
1030
+ def self.contains_slice?
1031
+ @@contains_slice_p||= ->(slice) { any?.(starts_with.(slice)) * tails }
1032
+ end
1033
+
1034
+ def self.all?
1035
+ @@all_p||= ->(f) { ->(x) { x == Nothing } * find_where.(->(x) { !f.(x)})}
1036
+ end ## this is going to become equal.(Nothing) * first * find_where.(F.not.(f))
1037
+
1038
+ def self.any?
1039
+ @@any_p||= ->(f) { ->(x) { x != Nothing } * find_where.(f)}
1040
+ end
1041
+
1042
+ def self.fold
1043
+ @@fold||= ->(fn, u) { final * scanl.(fn, u) }
1044
+ end
1045
+
1046
+ def self.slice_by
1047
+ @@slice_by||= ->(starts_with_fn, ends_with_fn) { take_until.(ends_with_fn) * drop_until.(starts_with_fn) }
1048
+ end
1049
+
1050
+ def self.interleave
1051
+ @@interleave||= ->(xs, *ys) { ys.length > 0 ? (concat * zip).(*([xs]+ys)) : ->(zs, *ys) { concat << zip.(*([xs,zs]+ys)) } }
1052
+ end ## you can undo this with % n, where n is the number of streams
1053
+
1054
+ def self.intercalate
1055
+ @@intercalate||= ->(xs, xss) { concat.intersperse.(xs, xss) }
1056
+ end
1057
+
1058
+ def self.partition_by
1059
+ @@partition_by||= ->(fn) {
1060
+ folded_filter = ->(f) { foldl.(->(acc, el) { f.(el) ? acc << el : acc }, []) }
1061
+ (folded_filter.(fn) + folded_filter.(->(x) { !fn.(x) })) * to_stream
1062
+ }
1063
+ end
1064
+
1065
+ def self.partition_at
1066
+ @@partition_at||= ->(n) { take.(n) + drop.(n) }
1067
+ end
1068
+
1069
+ def self.split_by
1070
+ @@split_by = ->(fn) { take_while.(fn) + drop_while.(fn) }
1071
+ end
1072
+
1073
+ def self.sum_of_square_difference_from_mean_two_pass
1074
+ @@sum_of_square_difference_from_mean_two_pass||= ->(l) { sum * map.(square * sub_by.(mean.(l))) << l }
1075
+ end
1076
+
1077
+ def self.last_index_of
1078
+ @@last_index_of||= ->(x) { last_index_where.(F.equal.(x)) }
1079
+ end
1080
+
1081
+ def self.first_index_of
1082
+ @@first_index_of||= ->(x) { first_index_where.( F.equal.(x) ) }
1083
+ end
1084
+
1085
+ def self.union
1086
+ @@union||= ->(xs) {
1087
+ ->(ys) {
1088
+ to_stream * to_set << append.(xs, ys)
1089
+ } * to_stream
1090
+ } * to_stream
1091
+ end
1092
+
1093
+ def self.interesect
1094
+ @@intersect||= ->(xs) {
1095
+ ->(ys) {
1096
+ to_stream << (to_set.(xs) & to_set.(ys))
1097
+ } * to_stream
1098
+ } * to_stream
1099
+ end
1100
+
1101
+ def self.difference
1102
+ @@difference||= ->(xs) {
1103
+ ->(ys) {
1104
+ to_remove = to_set.(ys)
1105
+ filter.(->(x) { !ys.include?(x)}) << xs
1106
+ } * to_stream
1107
+ } * to_stream
1108
+ end
1109
+
1110
+ def self.cartesian_product
1111
+ @@cartesian_product||= ->(xs) {
1112
+ ->(ys) {
1113
+ flatmap.(->(x) { map.(->(y) { [x,y] }, ys) }, xs)
1114
+ } * to_stream
1115
+ } * to_stream
1116
+ end
1117
+
1118
+ def self.unzip
1119
+ @@unzip||= ->(xs) {
1120
+ map.(first) + map.(last) << xs
1121
+ } * to_stream
1122
+ end
1123
+
1124
+ def self.bucket_by
1125
+ @@bucket_by||= ->(fn, xs) {
1126
+ foldl.(->(acc, el) {
1127
+ key = fn.(el)
1128
+ acc[key] ||= []
1129
+ acc[key] << el
1130
+ acc
1131
+ }, {}).(to_stream.(xs))
1132
+ }
1133
+ def self.bucket_by_and_summarize
1134
+ @@bucket_by_and_summarize||= ->(group_fn, summary_fn) {
1135
+ map.(summary_fn) * bucket_by.(group_fn)
1136
+ }
1137
+ end
1138
+
1139
+ def self.window
1140
+ @@window||= ->(n) {
1141
+ map.(take.(n)) * suffixes
1142
+ }
1143
+ end
1144
+
1145
+ def self.subsequences
1146
+ @@subsequences||= ->() { ## Using the applicative instance for <**>, which is ^ in Raskell
1147
+ subs = ->(ys) { ys == empty ? wrap.(empty) : subs.(rest.(ys)) ^ [F.id, F.cons.(first.(ys))].to_stream }
1148
+ }.() #wrap.(empty)
1149
+ end
1150
+ ## Using Control.Applicative
1151
+ # subs [] = [[]]
1152
+ # subs (@@x||=xs) = subs xs <**> [id, (x :)]
1153
+ ## subsequences is useful for fuzzy sequence matching style algorithms a la command tab in sublime,
1154
+ ### or figuring out if some melody or progressionis an elaboration of another (same thing), etc...
1155
+ ## is there any way to do this with a left fold instead of a right one?
1156
+
1157
+
1158
+ def self.continuous_subsequences
1159
+ @@continuous_subsequences||= filter.(F.not * empty?) * flatmap.(prefixes) * suffixes
1160
+ end
1161
+ ## continuous subsequences is useful for exact inside sequence matching a la find in sublime
1162
+
1163
+ def self.quicksort
1164
+ ->(xs) {
1165
+ if empty?.(xs)
1166
+ empty
1167
+ else
1168
+ pivot = head.(xs)
1169
+ partitions = (F.map.(self.quicksort) * partition_by.(F.is_lte.(pivot)) << tail.(xs)).to_a
1170
+ append.(partitions[0],cons.(pivot, partitions[1]))
1171
+ end
1172
+ } * to_stream ### if only this wasn't infinitely recursing...
1173
+ end
1174
+
1175
+ def self.group_by
1176
+ @@group_by||= ->(fn) {
1177
+ next_fn = ->(state) {
1178
+ strm = state.last
1179
+ group = state.first
1180
+ next_item = strm.next_item
1181
+ tag = next_item.first
1182
+ val = next_item[1]
1183
+ next_stream = next_item.last
1184
+ if tag == :done && group == []
1185
+ [:done]
1186
+ elsif tag == :done
1187
+ [:yield, group, empty]
1188
+ elsif tag == :skip
1189
+ [:skip, Stream.new(next_fn, [group, next_stream])]
1190
+ elsif tag == :yield && (group.length == 0 || fn.(val) == fn.(group.last))
1191
+ [:skip, Stream.new(next_fn, [group + [val], next_stream])]
1192
+ elsif tag == :yield
1193
+ [:yield, group, Stream.new([[], next_stream])]
1194
+ else
1195
+ raise "#{next_item} is a malformed stream response!"
1196
+ end
1197
+ }
1198
+ Stream.new(next_fn, [[], state])
1199
+ } * to_stream
1200
+ end
1201
+
1202
+ def self.lines_from_file
1203
+ @@lines_from_file||= ->(filepath, options={}) {
1204
+ (options['separator'] ? IO.foreach(filepath, options['separator']) : IO.foreach(filepath) ).to_stream
1205
+ }
1206
+ end
1207
+
1208
+ def self.group
1209
+ @@group||= ->(xs) { group_by.(id) }
1210
+ end
1211
+ end
1212
+ #std
1213
+
1214
+ class Stream
1215
+
1216
+ def deep_clone
1217
+ Stream.new(self.next_item_function, self.state.deep_clone)
1218
+ end
1219
+
1220
+ def [](first, last=-1)
1221
+ if last == -1
1222
+ i = first
1223
+ F.first * F.drop.(i)
1224
+ elsif first < 0 && last < 0
1225
+ F.drop_except.(last.abs - 1) * F.drop_except.(first.abs) << self
1226
+ ##todo
1227
+ else
1228
+ raise ""
1229
+ end
1230
+
1231
+ end
1232
+
1233
+ =begin ## ruby doesn't allow you to override the return value on []=, which means we'd have to destructively alter this Stream
1234
+ ## but for some reason that isn't working very well - probably due to the need for self-reference. Guess my deep_clone isn't working 100%?
1235
+ def []=(index, item)
1236
+ next_fn = ->(state) {
1237
+ i = state.first
1238
+ strm = state.last
1239
+ if
1240
+ [:yield, item, strm.next_item.last]
1241
+ else
1242
+ next_item = strm.next_item
1243
+ tag = next_item.first
1244
+ val = next_item[1]
1245
+ next_stream = next_item.last
1246
+ if tag == :done && i < index
1247
+ [:skip, F.snoc(item, Array.new(index - i-1, Nothing).to_stream)]
1248
+ elsif tag == :skip
1249
+ [:skip, Stream.new(next_fn, next_stream)]
1250
+ elsif tag == :yield && i == index
1251
+ [:yield, item, next_stream]
1252
+ elsif tag == :yield
1253
+ [:yield, val, Stream.new(next_fn, next_stream)]
1254
+ else
1255
+ raise "#{next_item} is a malformed stream response"
1256
+ end
1257
+ end
1258
+ }
1259
+ state = [0, self.deep_clone]
1260
+ self.next_item_function = next_fn
1261
+ self.state = state
1262
+ end
1263
+ =end
1264
+
1265
+ def first
1266
+ F.first.(self)
1267
+ end
1268
+
1269
+ def last
1270
+ F.last.(self)
1271
+ end
1272
+
1273
+ def rest
1274
+ F.rest.(self)
1275
+ end
1276
+
1277
+ def any?(fn=F.id)
1278
+ F.any?(fn) << self
1279
+ end
1280
+
1281
+ def all?(fn=F.id)
1282
+ F.all?(fn) << self
1283
+ end
1284
+
1285
+ ## Applicative <**>
1286
+ ## [1,2,3] ** [id, double]
1287
+ ## [1,2,2,4,3,6]
1288
+ ## defaults to cartesian product if you haven't got any procs in there
1289
+ def ^(stream_of_fns, is_cartesian=false)
1290
+ is_cartesian || !F.any?.(->(x) { x.kind_of? Proc }) ? self.cartesian_product.(stream_of_fns) : F.flatmap.(->(x) { stream_of_fns.(x).to_stream }).(self)
1291
+ end
1292
+
1293
+ ## zip or Applicative <*> depending on if there any function values in the array/stream ## or should it be interleave to go with % below?
1294
+ #[id, double] * [1,2,3]
1295
+ #[1,2,3,2,4,6]
1296
+ def **(stream, is_zip=false)
1297
+ is_zip || !F.any?.(->(x){ x.kind_of? Proc }) ? F.zip.(self, stream) : F.flatmap.(->(f) { F.map.(f) << stream.to_stream }).(self.to_stream)
1298
+ end
1299
+
1300
+ def *(stream) ## * and % are opposites
1301
+ F.interleave.(self, stream)
1302
+ end
1303
+
1304
+ ## %2 is odds, rest %2 is evens. doing % 3 breaks into every third item. % n does every nth as a stream
1305
+ ## [odds, evens].(interleave.(xs,ys)) == [xs,ys]
1306
+ def %(n=2)
1307
+ F.filter.(->(x) { x % n == 0}).(self)
1308
+ end
1309
+
1310
+ def +(stream)
1311
+ F.append.(self, stream)
1312
+ end
1313
+
1314
+ def -(stream)
1315
+ F.difference.(self, stream)
1316
+ end
1317
+
1318
+ ## this kind of conflicts with | being function pipelining - maybe change that to use < and > instead of * and | so we can keep ruby-ishness
1319
+ ## but we'll still need something for >>=, <**>, <$> and <.> later...
1320
+
1321
+ def |(stream) #
1322
+ F.union.(self, stream)
1323
+ end
1324
+
1325
+ def &(stream)
1326
+ F.intersect.(self, stream)
1327
+ end
1328
+ end
1329
+
1330
+ class Array
1331
+
1332
+ ## Applicative <**>
1333
+ ## [1,2,3] ** [id, double]
1334
+ ## [1,2,2,4,3,6]
1335
+ def ^(arr, is_cartesian=false)
1336
+ is_cartesian || !arr.any?{|x| x.kind_of? Proc } ? self.cartesian_product(arr) : F.flatmap.(->(x) { arr.to_stream.(x) }).(self).to_a
1337
+ end
1338
+
1339
+ ## cartesian product
1340
+
1341
+ def cartesian_product(arr)
1342
+ self.map {|x| arr.to_a.map { |y| [x,y] } }.foldl(->(acc,el) { acc.push(el) }, [])
1343
+ end
1344
+
1345
+ ## zip or Applicative <*> depending on if there any function values in the array/stream
1346
+ #[id, double] * [1,2,3]
1347
+ #[1,2,3,2,4,6]
1348
+ def **(arr, is_zip=false)
1349
+ is_zip || !self.any?{|x| x.kind_of? Proc } ? self.zip(arr.to_a) : F.flatmap.(->(f) { F.map.(f) << arr.to_stream }).(self.to_stream).to_a
1350
+ end
1351
+
1352
+
1353
+ end
1354
+
1355
+ class Enumerator
1356
+
1357
+ def self.to_stream(enum)
1358
+ enumerator_to_use = enum.clone.lazy
1359
+ enumerator_to_store = enumerator_to_use.clone
1360
+
1361
+ next_fn = ->(state) {
1362
+ idx = state[0]
1363
+ enum_frozen = state[1]
1364
+ enum_next = state[2]
1365
+
1366
+ next_state = [idx+1, enum_frozen, enum_next]
1367
+ next_tag = :yield
1368
+ begin
1369
+ begin
1370
+ next_item = enum_next.next
1371
+
1372
+ rescue StopIteration => e
1373
+ next_tag = :done
1374
+ end
1375
+ rescue IOError => e
1376
+ next_state = [idx, enum_frozen, enum_frozen.clone.drop(i)]
1377
+ next_tag = :skip
1378
+ end
1379
+ ## this {@@type||= "enumerator" is a dirty hack - there has to be a better way to restore state after calling next_item}
1380
+ next_tag == :done ? [:done] : [next_tag] + (next_tag == :yield ? [next_item] : []) + [Stream.new(next_fn, next_state, {type: "enumerator"})]
1381
+
1382
+ }
1383
+ Stream.new(next_fn, [0, enumerator_to_store, enumerator_to_use], {type: "enumerator"})
1384
+ end
1385
+
1386
+ def to_stream
1387
+ self.class.to_stream(self)
1388
+ end
1389
+
1390
+ end
1391
+
1392
+ =begin
1393
+ ## functionals useful for lists ( but which work on anything supporting .each, and will yield a list )
1394
+
1395
+
1396
+
1397
+ updated
1398
+
1399
+ last_index_of_slice
1400
+ first_index_of_slice
1401
+ nth
1402
+ index_of
1403
+ index_where
1404
+ findIndex?
1405
+
1406
+ random
1407
+ randomN
1408
+ segmentLength
1409
+
1410
+
1411
+
1412
+ splice
1413
+ patch
1414
+ span
1415
+
1416
+ permutations
1417
+ combinations
1418
+
1419
+ sort_by ## insertionSort
1420
+ scanr
1421
+
1422
+ ## functionals useful in untyped languages like ruby - arbitrarily deep map, zip, and merge - and deep_clone
1423
+
1424
+ deep_map ## for a dictionary, maps across all its values deep until not-a-dictionary
1425
+ ## for a list, maps across all its values deep until not-a-list
1426
+ ## in general, it just deeply applies fmap with a particular kind it should only apply to
1427
+ deep_map_ ## keeps going no matter what the kind is, as long as it supports fmap
1428
+ deep_zip
1429
+ deep_merge ## implement with deep_zip and deep_map
1430
+ deep_diff ## implement with deep_zip and deep_map
1431
+
1432
+ =end
1433
+
1434
+
1435
+ =begin The below is for later implementation
1436
+
1437
+
1438
+ quicksort ## use stream fusion == quicksort
1439
+ mergesort ## use stream fusion
1440
+
1441
+ deepMap
1442
+ deepZip
1443
+ deepMerge
1444
+
1445
+ hylo # unfoldl . foldl
1446
+ meta # foldl . unfoldl
1447
+
1448
+ =end