raskell 0.1.2 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fe20c829bf17d4522fc5cb6359be0f2c4609e324
4
- data.tar.gz: 13ea0fe6cc5e1568e89580cadb2b3d5a846a33a2
3
+ metadata.gz: 0e133ee451e2be310983090109ed99d82b8fa1ef
4
+ data.tar.gz: 9ce3847f6ebe54b79faf505f35f867c65a8e3ea3
5
5
  SHA512:
6
- metadata.gz: 2af3ff60eadb54244f972c5f092c96a55e83a2641a0c0ea16974006a4a2945fff2a57ef0ad1ef6bc7dbf08722dadd619b611d413068e4c25f0e88a26e3957603
7
- data.tar.gz: ea9dec9a5b3c8e16f72dc8382c4f74ed570727af0715586f662214129be9aead795a1736ba76eaead07fee4a1a729cc42d7abaf9d16d543d755f1bab5c67651a
6
+ metadata.gz: 66bef77ff5951dab5c044da8bedcea9b089ad883aa3391e3d6236cdf75b2aab21881895a90150b740211bc015d90682d3e957f1100ab4d8dfd0031a8d27fc5ee
7
+ data.tar.gz: d5321834069742a61bbcd293e1522922677da1b55ff7e2cba70d2d3b5b677907aebddaf1e030ee0974dde2d8846207ca9b2f553117916d376e3f25dd549e6860
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # raskell
2
- Making Ruby a Joy to Work With
2
+ Functional and Concatenative Stream Programming in Ruby
3
3
  =======
4
4
 
5
5
 
@@ -7,7 +7,7 @@ Usage:
7
7
 
8
8
  Reminder: Lambdas can be applied with [\*args] notation and .() is syntactic sugar for .call()
9
9
  ```f = ->(x) { x + 2 } ```
10
- ```f[1]``` evaluates as ```3```
10
+ ```f[1]``` , ```f.(1)```, and ```f.call(1)``` all evaluate as ```3```
11
11
 
12
12
 
13
13
  Lambdas can be partially applied, yielding a new lambda, with call
@@ -24,7 +24,7 @@ Lambda Composition with \* (right-associative) ```( (f * g * h).(x) == f.(g.(h.(
24
24
  ```(double * minus3 * times10).(5)``` evaluates as ```94```
25
25
 
26
26
 
27
- Lambda Pipelining with \| (left-associative) ``` (f | g | h).(x) == h.(g.(f.(x))) ```
27
+ Lambda Pipelining with \| (left-associative) ```(f | g | h).(x) == h.(g.(f.(x)))```
28
28
  ```(times10 | minus3 | double).(5)``` evaluates as ```94```
29
29
  ```(double | minus3 | times10).(5)``` evaluates as ```70```
30
30
 
@@ -32,20 +32,20 @@ Lambda Tupling with + (associative)
32
32
  ```(times10 + minus3 + double).(5)``` evaluates as ```[50, 2, 10]```
33
33
 
34
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```
35
+ ```5.(1,2,3,[4,7])``` evaluates to ```5```
36
36
 
37
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```
38
+ ```[times10, minus3, double].(5)``` evaluates to ```[50, -15, 10]```
39
39
  ```[plus, times10, 3].(0,1)``` evaluates to ```[1, 0, 3]```
40
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
41
 
42
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```
43
+ ```[times10, minus3, double].to_stream.(5).to_a``` evaluates to ```[50, -15, 10]```
44
44
  ```[plus, times10, 3].to_stream.(0,1)``` evaluates to ```[1, 0, 3].to_stream```
45
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
46
 
47
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]```
48
+ ```F.map.(times10 * plus10).([1,2,3])``` evaluates as ```[100, 200, 300]```
49
49
 
50
50
 
51
51
 
@@ -65,7 +65,7 @@ Available Operators to Overload in Ruby
65
65
  Using in Raskell so far
66
66
  [], \*, \*\*, ^, \|, &, +, %, <<, >>
67
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
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 - this gives us a powerful form of type constraint for free
69
69
 
70
70
 
71
71
 
data/ROADMAP.md CHANGED
@@ -1,4 +1,4 @@
1
- Making Ruby a "Joy" to Work With In X (Easy?) Steps
1
+ Making Ruby a Joy to Work With In X (Easy?) Steps
2
2
 
3
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
4
  \*II) function tupling, composition, and pipelining in the form of +,\*, and \|
@@ -6,10 +6,7 @@ Making Ruby a "Joy" to Work With In X (Easy?) Steps
6
6
  \*IV) a standard collections library based around fusable stream transducers - (flat)map, filter, fold\*, zip, append, scanl - Scala/Haskell eqv.
7
7
  \*V) add instances of from_stream(ClassName=Array) and to_stream for Dictionary, (Multi?)Set, Array, Range, String, Integer, Object, and Enumerable
8
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
9
+ \*VII) Implement Applicative instances for Proc, Array, and Stream
10
+ VII) modularize for easy addition into other's projects, organize code and test coverage (Procish), reduce code duplication
11
+ IX) Document, let simmer with experience, and optimize
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
@@ -1,1217 +1,1249 @@
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()
1
+ module System
2
+ module Collections
3
+ module ObjectLambdas
4
+ extend self
5
+
6
+ def id
7
+ Identity.new # ->(x) { x }
8
+ end
9
+
10
+ def equals
11
+ @@equals||= ->(x,y) { x == y }
12
+ end
13
+
14
+ def equal
15
+ @@equal||= ->(x,y) { x == y }
16
+ end
17
+
18
+ def eq
19
+ @@eq||= ->(x,y) { x === y }
20
+ end
21
+
22
+ def list
23
+ @@list||= ->(*items) { items }
24
+ end
16
25
  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
26
 
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
27
 
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)
28
+ module ProcishLambdas
29
+ extend self
30
+
31
+ def apply_with2
32
+ @@apply_with2||= ->(y, f, x) { f.(x,y)}
90
33
  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
34
 
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
35
+ def apply
36
+ @@apply||= ->(f, *xs) { f.(*xs) }
37
+ end
38
+
39
+ def apply_fn
40
+ @@apply_fn||= -> (f, *args) { f.(*args)}
41
+ end
42
+
43
+ def apply_with
44
+ @@apply_with||= ->(x,f) { f.(x) } # flip * apply
45
+ end
46
+
47
+ def compose
48
+ @@compose||= ->(f,g) { f * g }
49
+ end
50
+
51
+ def flip
52
+ @@flip||= -> (f,x,y) { f.(y,x) }
53
+ end
54
+
55
+ def slf
56
+ @@slf||= -> (f, x) { f.(x,x) } ## square = slf * times
57
+ end
58
+
59
+ def repeat
60
+ @@repeat||= ->(n, fn, x) {
61
+ result = x
62
+ count = n
63
+ while count > 0
64
+ result = fn.(result)
65
+ end
66
+ result
67
+ }
68
+ end
69
+
70
+ def fix
71
+ @@fix||= ->(f, x) {
72
+ result = x
73
+ next_result = f.(x)
74
+ while result != next_result
75
+ result = next_result
76
+ next_result = f.(result)
77
+ end
78
+ result
79
+ }
80
+ end
81
+
82
+ ## next_stream_fn yields Nothing for stop, and the next stream to go to otherwise
83
+ ## yield_fn yields a Nothing for skip, and the next value to yield otherwise
84
+ def cstep
85
+ @@cstep||= ->(next_stream_fn, yield_fn) {
86
+ ## next_stream_fn :: state -> next_fn -> Maybe(stream)
87
+ ## yield_fn :: state -> Maybe(item)
88
+ next_fn = ->(state) {
89
+ next_stream = next_stream_fn.(state)
90
+ to_yield = yield_fn.(state)
91
+ if next_stream == Nothing
92
+ [:done]
93
+ elsif to_yield == Nothing
94
+ [:skip, next_stream]
95
+ else
96
+ [:yield, to_yield, next_stream]
97
+ end
98
+ }
99
+ next_fn
100
+ }
101
+ end
102
+
103
+ def step
104
+ @@step||= ->(transition_fn, yield_fn) {
105
+ ## transition_fn :: state -> Maybe(state)
106
+ ## yield_fn :: state -> Maybe(item)
107
+ next_fn = ->(state) {
108
+ next_state = transition_fn.(state)
109
+ to_yield = yield_fn.(state) if next_state != Nothing
110
+ if next_state == Nothing
111
+ [:done]
112
+ elsif to_yield == Nothing
113
+ [:skip, Stream.new(next_fn, next_state)]
114
+ else
115
+ [:yield, to_yield, Stream.new(next_fn, next_state)]
116
+ end
117
+ }
118
+ next_fn
119
+ }
120
+ end
121
+
122
+ def unfoldl
123
+ @@unfoldl||= -> (next_fn, stop_fn, seed) {
124
+ Stream.new(step.(->(state) { stop_fn.(state) ? Nothing : next_fn.(state) }, next_fn ), seed)
125
+ }
126
+ end
127
+ end
168
128
 
169
- def self.plus
170
- @@plus||= ->(x,y) { x + y }
171
- end
129
+ module BooleanLambdas
130
+ extend self
131
+
132
+ ## booleans
133
+ def not
134
+ @@not||= ->(x) { !x }
135
+ end
136
+
137
+ def and
138
+ @@and||= ->(x,y) { x && y }
139
+ end
140
+
141
+ def nand
142
+ @@nand||= ->(x,y) { !(x && y) }
143
+ end
144
+
145
+ def or
146
+ @@or||= ->(x,y) { x || y }
147
+ end
148
+
149
+ def nor
150
+ @@nor||= ->(x,y) { !x && !y }
151
+ end
152
+
153
+ def xor
154
+ @@xor||= ->(x,y) { !(x && y) && (x || y) }
155
+ end
156
+
157
+ def ands
158
+ @@ands||= ->(x) { x == Nothing } * find_where.(F.equals.(false))
159
+ end
160
+
161
+ def ors
162
+ @@ors||= ->(x) { x != Nothing } * find_where.(F.equals.(true))
163
+ end
164
+
165
+ end
166
+
167
+ module NumericLambdas
168
+ extend self
169
+
170
+ def infinity
171
+ Float::INFINITY
172
+ end
173
+
174
+ def negative_infinity
175
+ -Float::INFINITY
176
+ end
177
+
178
+ def inf
179
+ Float::INFINITY
180
+ end
181
+
182
+ def ninf
183
+ -Float::INFINITY
184
+ end
185
+
186
+ ## numbers
187
+ def inc
188
+ @@inc||= ->(x) { x + 1 }
189
+ end
190
+
191
+ def dec
192
+ @@dec||= ->(x) { x - 1 }
193
+ end
194
+
195
+ def plus
196
+ @@plus||= ->(x,y) { x + y }
197
+ end
198
+
199
+ def times
200
+ @@times||= ->(x,y) { x * y }
201
+ end
202
+
203
+ def sub_from
204
+ @@sub_from||= ->(x,y) { x - y }
205
+ end
206
+
207
+ def div_from
208
+ @@div_from||= ->(x,y) { x / y }
209
+ end
210
+
211
+ def div_by
212
+ @@div_by||= ->(y,x) { x / y}
213
+ end
214
+
215
+ def sub_by
216
+ @@sub_by||= ->(y,x) { x - y}
217
+ end
218
+
219
+ def is_gt
220
+ @@is_gt||= ->(y,x) { x > y }
221
+ end
222
+
223
+ def is_lt
224
+ @@is_lt||= ->(y,x) { x < y }
225
+ end
226
+
227
+ def is_gte
228
+ @@is_gte||= ->(y,x) { x >= y }
229
+ end
230
+
231
+ def is_lte
232
+ @@is_lte||= ->(y,x) { x <= y }
233
+ end
234
+
235
+ def gt
236
+ @@gt||= ->(x,y) { x > y }
237
+ end
238
+
239
+ def lt
240
+ @@lt||= ->(x,y) { x < y }
241
+ end
242
+
243
+ def gte
244
+ @@gte||= ->(x,y) { x >= y }
245
+ end
246
+
247
+ def lte
248
+ @@lte||= ->(x,y) { x <= y }
249
+ end
250
+
251
+ #insert ln, lg, log, log_base, e, pi, exp/pow, square, cube, nth_root, sqrt here later
252
+ def max
253
+ @@max||= ->(x,y) { x >= y ? x : y}
254
+ end
255
+
256
+ def min
257
+ @@min||= ->(x,y) { x <= y ? x : y}
258
+ end
259
+
260
+ def double
261
+ @@double||= slf.(plus)
262
+ end
263
+
264
+ def square
265
+ @@square||= slf.(times)
266
+ end
267
+
268
+
269
+ end
270
+
271
+ module FoldableStreamLambdas
272
+ def foldleft
273
+ @@foldleft||= ->(f,u) {
274
+
275
+ ->(stream) {
276
+ next_item = stream.next_item
277
+ result = u
278
+ while next_item != [:done]
279
+ if next_item.first == :skip
280
+
281
+ elsif next_item.first == :yield
282
+ result = f.(result, next_item[1])
283
+ else
284
+ raise "#{next_item} is a malformed stream response"
285
+ end
286
+ next_item = next_item.last.next_item
287
+ end
288
+ result
289
+ } * to_stream
290
+
291
+ }
292
+ end
172
293
 
173
- def self.times
174
- @@times||= ->(x,y) { x * y }
175
- end
294
+ def foldr
295
+ @@foldr||= ->(f,u) {
296
+ ->(stream) {
297
+ next_item = stream.next_item
298
+ if next_item == [:done]
299
+ u
300
+ elsif next_item.first == :skip
301
+ foldr.(f, u, next_item.last)
302
+ elsif next_item.first == :yield
303
+ f.(next_item[1], foldr.(f, u, next_item.last))
304
+ else
305
+ raise "#{next_item} is improperly formed for a Stream"
306
+ end
307
+ } * to_stream
308
+
309
+ }
310
+ end
176
311
 
177
- def self.sub_from
178
- @@sub_from||= ->(x,y) { x - y }
179
- end
312
+ def partition_by
313
+ @@partition_by||= ->(fn) {
314
+ folded_filter = ->(f) { foldl.(->(acc, el) { f.(el) ? acc << el : acc }, []) }
315
+ (folded_filter.(fn) + folded_filter.(->(x) { !fn.(x) })) * to_stream
316
+ }
317
+ end
318
+
319
+ def bucket_by
320
+ @@bucket_by||= ->(fn, xs) {
321
+ foldl.(->(acc, el) {
322
+ key = fn.(el)
323
+ acc[key] ||= []
324
+ acc[key] << el
325
+ acc
326
+ }, {}).(to_stream.(xs))
327
+ }
328
+ end
329
+
330
+ def bucket_by_and_summarize
331
+ @@bucket_by_and_summarize||= ->(group_fn, summary_fn) {
332
+ map.(summary_fn) * bucket_by.(group_fn)
333
+ }
334
+ end
180
335
 
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
336
 
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
337
+ end
245
338
 
246
- ## streams
247
- def self.empty
248
- @@empty||= Stream.new(->(x) { [:done] }, Nothing)
249
- end
339
+ module OneForOneStreamLambdas
340
+ extend self
341
+
342
+ def mapleft
343
+ @@mapleft||= ->(fn) {
344
+ ->(stream) {
345
+ next_fn = ->(state) {
346
+ next_el = state.next_item
347
+ if next_el == [:done]
348
+ [:done]
349
+ elsif next_el.first == :skip
350
+ [:skip, Stream.new(next_fn, next_el.last)]
351
+ elsif next_el.first == :yield
352
+ [:yield, fn.(next_el[1]), Stream.new(next_fn, next_el.last)]
353
+ else
354
+ raise "#{next_el.inspect} is not a valid stream state!"
355
+ end
356
+ }
357
+ Stream.new(next_fn, stream)
358
+ } * to_stream
359
+ }
360
+ end
250
361
 
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
362
+ def scanleft
363
+ @@scanleft||= ->(f,u) {
364
+ ->(stream) {
365
+ next_fn = ->(state) {
366
+ result_so_far = state.first
367
+ strm = state.last
368
+ next_item = strm.next_item
369
+ tag = next_item[0]
370
+ val = next_item[1]
371
+ next_stream = next_item.last
372
+ if tag == :done
373
+ [:done]
374
+ elsif tag == :skip
375
+ [:skip, Stream.new(next_fn, [result_so_far, next_stream])]
376
+ elsif tag == :yield
377
+ new_result = f.(result_so_far, val)
378
+ [:yield, new_result, Stream.new(next_fn, [new_result, next_stream]) ]
379
+ else
380
+ raise "#{next_item} is a malformed stream response"
381
+ end
382
+ }
383
+ Stream.new(next_fn, [u, stream])
384
+ } * to_stream
385
+
386
+ }
387
+ end
257
388
 
258
- def self.cons
259
- @@cons||= ->(el) {
260
- ->(stream) {
261
- Stream.new(->(x) { [:yield, el, stream] } , Nothing)
262
- } * to_stream
263
- }
264
- end
389
+ def zip_with
390
+ @@zip_with||= ->(fn) {
391
+ ->(left_stream, right_stream, *streams) {
392
+ streams = ([left_stream, right_stream] + streams).map(&:to_stream)
393
+ next_fn = ->(state) {
394
+ val_so_far = state.first
395
+ strms = state.drop(1)
396
+ next_stream = strms.first
397
+ next_item = next_stream.next_item
398
+ new_streams = strms.drop(1) + [next_stream.next_item.last == :done ? empty : next_item.last]
399
+ tag = next_item.first
400
+ val = tag == :done ? nil : next_item[1]
401
+ if tag == :done
402
+ [:done]
403
+ elsif tag == :skip
404
+ [:skip, Stream.new(next_fn, [val_so_far] + new_streams)]
405
+ elsif tag == :yield && val_so_far.length == streams.length - 1
406
+ [:yield, fn.(*(val_so_far + [val])), Stream.new(next_fn, [[]] + new_streams)]
407
+ elsif tag == :yield
408
+ [:skip, Stream.new(next_fn, [val_so_far + [val]] + new_streams)]
409
+ else
410
+ raise "#{next_item} is a malformed stream response!"
411
+ end
412
+ }
413
+
414
+ Stream.new(next_fn, [[]] + streams)
415
+ }
416
+ }
417
+ end
265
418
 
419
+ def replace_with
420
+ @@replace_with||= ->(to_replace_with, to_replace) { map.(->(x) { x == to_replace ? to_replace_with : x }) }
421
+ end
266
422
 
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
423
+ end
424
+
425
+ module HigherOrderStreamLambdas
426
+ extend self
427
+
428
+ def flatmap
429
+ @@flatmap||= ->(fn) {
430
+
431
+ ->(stream) {
432
+ next_fn = ->(next_el) {
433
+ state = next_el.first
434
+ potential_stream = next_el.last
435
+ if potential_stream == Nothing
436
+ next_el = state.next_item
437
+ if next_el == [:done]
438
+ [:done]
439
+ elsif next_el.first == :skip
440
+ [:skip, Stream.new(next_fn, [next_el.last, Nothing])]
441
+ elsif next_el.first == :yield
442
+ [:skip, Stream.new(next_fn, [next_el.last, fn.(next_el[1])])]
443
+ else
444
+ raise "#{next_el.inspect} is not a valid stream state!"
445
+ end
446
+ else
447
+ next_el = potential_stream.next_item
448
+ if next_el == [:done]
449
+ [:skip, Stream.new(next_fn, [state, Nothing])]
450
+ elsif next_el.first == :skip
451
+ [:skip, Stream.new(next_fn, [state, next_el.last])]
452
+ elsif next_el.first == :yield
453
+ [:yield, next_el[1], Stream.new(next_fn, [state, next_el.last])]
454
+ else
455
+ raise "#{next_el.inspect} is not a valid stream state!"
456
+ end
457
+ end
458
+ }
459
+ Stream.new(next_fn, [stream, Nothing])
460
+ } * to_stream
461
+
462
+ }
463
+ end
464
+
465
+ def filter
466
+ @@filter||= ->(fn) {
467
+ ->(stream) {
468
+ next_fn = ->(state) {
469
+ next_el = state.next_item
470
+ if next_el == [:done]
471
+ [:done]
472
+ elsif next_el.first == :skip || (next_el.first == :yield && !fn.(next_el[1]))
473
+ [:skip, Stream.new(next_fn, next_el.last)]
474
+ elsif next_el.first == :yield && fn.(next_el[1])
475
+ [next_el.first, next_el[1], Stream.new(next_fn, next_el.last)]
476
+ else
477
+ raise "#{next_el.inspect} is not a valid stream state!"
478
+ end
479
+ }
480
+ Stream.new(next_fn, stream)
481
+ } * to_stream
482
+ }
483
+ end
484
+
485
+ def find_where
486
+ @@find_where||= ->(fn){ first * filter.(fn) }
487
+ end
488
+
489
+ def find_last_where
490
+ @@find_last_where||= ->(fn){ last * filter.(fn) }
491
+ end
492
+
493
+ def first_index_where
494
+ @@first_index_where||= ->(fn) { first * find_where.( fn * last ) * zip_with_index }
495
+ end
496
+
497
+ def last_index_where
498
+ @@last_index_where||= ->(fn) { first * find_last_where.( fn * last ) * zip_with_index }
499
+ end
500
+
501
+ def all?
502
+ @@all_p||= ->(f) { ->(x) { x == Nothing } * find_where.(->(x) { !f.(x)})}
503
+ end ## this is going to become equal.(Nothing) * first * find_where.(F.not.(f))
504
+
505
+ def any?
506
+ @@any_p||= ->(f) { ->(x) { x != Nothing } * find_where.(f)}
272
507
  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
508
+
509
+ def slice_by
510
+ @@slice_by||= ->(starts_with_fn, ends_with_fn) { take_until.(ends_with_fn) * drop_until.(starts_with_fn) }
511
+ end
512
+
513
+ def split_by
514
+ @@split_by = ->(fn) { take_while.(fn) + drop_while.(fn) }
515
+ end
516
+
517
+ def group_by
518
+ @@group_by||= ->(fn) {
519
+ next_fn = ->(state) {
520
+ strm = state.last
521
+ group = state.first
334
522
  next_item = strm.next_item
335
523
  tag = next_item.first
336
524
  val = next_item[1]
337
- next_strm = next_item.last
338
- if tag == :done
525
+ next_stream = next_item.last
526
+ if tag == :done && group == []
339
527
  [:done]
528
+ elsif tag == :done
529
+ [:yield, group, empty]
340
530
  elsif tag == :skip
341
- [:skip, next_strm]
531
+ [:skip, Stream.new(next_fn, [group, next_stream])]
532
+ elsif tag == :yield && (group.length == 0 || fn.(val) == fn.(group.last))
533
+ [:skip, Stream.new(next_fn, [group + [val], next_stream])]
342
534
  elsif tag == :yield
343
- [:skip, next_strm]
535
+ [:yield, group, Stream.new([[], next_stream])]
344
536
  else
345
537
  raise "#{next_item} is a malformed stream response!"
346
538
  end
539
+ }
540
+ Stream.new(next_fn, [[], state])
541
+ } * to_stream
542
+ end
543
+
544
+ def window_by
545
+ @@window_by||= self.group_by ## basically, window_by is group_by, but where you pass it a relation (a true/false function) instead of an arbitrary function
546
+ end
547
+
548
+ end
549
+
550
+ module StreamLambdas
551
+ extend self
552
+
553
+
554
+ def empty?
555
+ @@empty_p||= F.equal.(empty)
556
+ end
557
+
558
+ def null?
559
+ @@null_p||= F.equal.(empty)
560
+ end
561
+
562
+ def empty
563
+ @@empty||= Stream.new(->(x) { [:done] }, Nothing)
564
+ end
565
+
566
+ def wrap
567
+ @@wrap||= ->(x) {
568
+ next_fn = ->(bool) { bool ? [:yield, x, Stream.new(next_fn, false)] : [:done]}
569
+ Stream.new(next_fn, true)
570
+ }
571
+ end
572
+
573
+ def cons
574
+ @@cons||= ->(el) {
575
+ ->(stream) {
576
+ Stream.new(->(x) { [:yield, el, stream] } , Nothing)
577
+ } * to_stream
578
+ }
579
+ end
580
+
581
+
582
+ def first
583
+ @@first||= -> (stream) { ## should offer an equivalent that returns a stream with a single element
584
+ next_item = stream.next_item
585
+ while next_item.first == :skip
586
+ next_item = next_item.last.next_item
347
587
  end
588
+ next_item.first == :yield ? next_item[1] : Nothing
589
+ } * to_stream
590
+ end
591
+
592
+ def rest
593
+ @@rest||= -> (stream) {
594
+ next_item = stream.next_item
595
+ next_item == [:done] ? Nothing : next_item.last
596
+ } * to_stream
597
+ end
598
+
599
+ def snoc
600
+ @@snoc||= ->(el) {
601
+
602
+ ->(stream) {
603
+ # next_fn = step.(->(stream) {
604
+ # next_item = stream.next_item
605
+ # next_item == [:done] ? wrap.(el) : next_item.last
606
+ # },
607
+ # ->(stream) {
608
+ # next_item = stream.next_item
609
+ # next_item.first == :skip ? Nothing : next_item[1]
610
+ # })
611
+ next_fn = ->(s) {
612
+ next_item = s.next_item
613
+ if next_item == [:done]
614
+ [:skip, wrap.(el)]
615
+ elsif next_item.first == :skip
616
+ [:skip, Stream.new(next_fn, next_item.last)]
617
+ elsif next_item.first == :yield
618
+ [:yield, next_item[1], Stream.new(next_fn, next_item.last)]
619
+ else
620
+ raise "#{next_item} is a malformed stream result"
621
+ end
622
+ }
623
+ Stream.new(next_fn, stream)
624
+ } * to_stream
348
625
  }
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))
626
+ end
627
+
628
+ def init
629
+ @@init||= ->(stream) {
630
+ next_fn = ->(state) {
631
+ strm = state.last
632
+ next_item = strm.next_item
633
+ if next_item == [:done] && state.first == Nothing
634
+ raise "init requires a stream length of at least 1"
635
+ elsif next_item == [:done]
387
636
  [: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)]
637
+ elsif next_item.first == :skip
638
+ [:skip, Stream.new(next_fn, [state.first, next_item.last])]
639
+ elsif next_item.first == :yield && state.first == Nothing
640
+ [:skip, Stream.new(next_fn, [next_item[1], next_item.last])]
641
+ elsif next_item.first == :yield
642
+ [:yield, state.first, Stream.new(next_fn, [next_item[1], next_item.last])]
392
643
  else
393
- raise("#{next_item} is a malformed stream response!")
644
+ raise "#{next_item} is a malformed stream response"
394
645
  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]
646
+ }
647
+ Stream.new(next_fn, [Nothing, stream])
648
+ } * to_stream
649
+ end
650
+
651
+ def append
652
+ @@append||= ->(left_stream) {
653
+ ->(right_stream) {
654
+ left_next_fn = ->(stream) {
655
+ next_el = stream.next_item
656
+ if next_el == [:done]
657
+ [:skip, right_stream]
658
+ elsif next_el.first == :skip
659
+ [:skip, Stream.new(left_next_fn, next_el.last)]
660
+ elsif next_el.first == :yield
661
+ [next_el.first, next_el[1], Stream.new(left_next_fn, next_el.last)]
662
+ else
663
+ raise "#{next_el.inspect} is not a valid stream state!"
664
+ end
665
+ }
666
+
667
+ Stream.new(left_next_fn, left_stream)
668
+ } * to_stream
669
+
670
+ } * to_stream
671
+ end
672
+
673
+ def concat
674
+ @@concat||= flatmap.(to_stream)
675
+ end
676
+
677
+ def enconcat
678
+ @@enconcat||= ->(left_stream, el) { append.(left_stream.to_stream) * cons.(el) * to_stream }
679
+ end
680
+
681
+ def initial
682
+ @@initial||= ->(stream) {
683
+ next_fn = ->(strm) {
684
+ next_item = strm.next_item
685
+ if next_item.first == :done
686
+ raise "Must have at least one item inside of the stream!"
687
+ elsif next_item.first == :yield
688
+ [:yield, next_item[1], empty]
689
+ elsif next_item.first == :skip
690
+ [:skip, next_item.last]
416
691
  else
417
692
  raise("#{next_item} is a malformed stream response!")
418
693
  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)]
694
+ }
695
+ Stream.new(next_fn, stream)
696
+ }
697
+ end
698
+
699
+ def final
700
+ @@final||= -> (stream) {
701
+ next_fn = ->(state) {
702
+ prev_step = state.first
703
+ strm = state.last
704
+ raise("Must have at least one item inside of the stream!") if prev_step == [:done]
705
+ next_item = strm.next_item
706
+ if prev_step.first == :skip
707
+ [:skip, Stream.new(next_fn, [next_item, next_item.last])]
708
+ elsif next_item == [:done]
709
+ [:yield, prev_step[1], empty]
710
+ elsif next_item.first == :yield
711
+ [:skip, Stream.new(next_fn, [next_item, next_item.last])]
712
+ elsif next_item.first == :skip
713
+ [:skip, Stream.new(next_fn, [prev_step, next_item.last])]
440
714
  else
441
- raise("#{next_item} is a malformed stream response!")
715
+ raise "#{next_item} is a malformed stream result"
442
716
  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]
717
+ }
718
+ next_item = stream.next_item
719
+ Stream.new(next_fn, [next_item, next_item.last])
720
+ } * to_stream
721
+ end
722
+
723
+
724
+ def rotate
725
+ @@rotate||= ->(s) { append.(tail.(s), initial.(s)) }
726
+ end
727
+
728
+
729
+ def interleave
730
+ @@interleave||= ->(xs, *ys) { ys.length > 0 ? (concat * zip).(*([xs]+ys)) : ->(zs, *ys) { concat << zip.(*([xs,zs]+ys)) } }
731
+ end ## you can undo this with % n, where n is the number of streams
732
+
733
+ def intercalate
734
+ @@intercalate||= ->(xs, xss) { concat.intersperse.(xs, xss) }
735
+ end
736
+
737
+ def suffixes
738
+ @@suffixes||= ->(stream) {
739
+ next_fn = ->(strm) {
740
+ next_item = strm.next_item
741
+ if next_item.first == :done
742
+ [:yield, strm, empty]
743
+ elsif next_item.first == :yield
744
+ [:yield, strm, Stream.new(next_fn, next_item.last)]
745
+ elsif next_item.first == :skip
746
+ [:skip, Stream.new(next_fn, next_item.last)]
464
747
  else
465
748
  raise("#{next_item} is a malformed stream response!")
466
749
  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
750
  }
751
+ Stream.new(next_fn, stream)
752
+ } * to_stream
753
+ end
754
+
755
+
756
+ def prefixes
757
+ @@prefixes||= foldr.(->(el, acc) { cons.(empty, map.(cons.(el), acc)) }, wrap.(empty))
758
+ end
759
+
760
+ ## stream functions
761
+ def last
762
+ @@last||= first * final
763
+ end
764
+
765
+ def uncons
766
+ @@uncons||= ->(s) { append(first.(l), wrap(rest.(l))) } * to_stream
767
+ end
768
+
769
+ def unsnoc
770
+ @@unsnoc||= ->(s) { append(wrap(init.(s)), last.(s)) } * to_stream
771
+ end
772
+
773
+ def reverse
774
+ @@reverse||= foldl.(->(acc, el) { cons.(el, acc) }, []) ## or foldr.(->(el,acc) { snoc.(acc, el) }
775
+ end
776
+
777
+ def length
778
+ @@length||= foldl.(inc, 0)
779
+ end
780
+
781
+ def length_at_least
782
+ @@length_at_least||= ->(n) { ->(x) { x != Nothing } * find_where.(equals.(n)) * scanl.(inc, 0) }
783
+ end
784
+
785
+ def replace
786
+ @@replace||= ->(to_replace, to_replace_with) {map.(->(x) { x == to_replace ? to_replace_with : x })}
787
+ end
788
+
789
+ def zip
790
+ @@zip||= zip_with.(list)
791
+ end
792
+
793
+ def zip_with_index
794
+ @@zip_with_index||= F.zip_with.(F.list).(F.range.(0, F.infinity))
795
+ end
796
+
797
+ def transpose
798
+ @@transpose||= ->(stream_of_streams) { zip.( *(stream_of_streams.to_stream) ) }
799
+ end
800
+
801
+ def tail
802
+ @@tail||= rest
803
+ end
804
+
805
+ def prefix
806
+ @@prefix||= init
807
+ end
808
+
809
+ def suffix
810
+ @@suffix||= rest
811
+ end
812
+
813
+ def head
814
+ @@head||= first
815
+ end
816
+
817
+ def inits
818
+ @@inits||= prefixes
819
+ end
820
+
821
+ def tails
822
+ @@tails||= suffixes
823
+ end
824
+
825
+ def starts_with?
826
+ @@starts_with||= ->(prefix, stream) { F.ands << zip_with.(equals, prefix, stream) }
827
+ end
828
+
829
+ def ends_with?
830
+ @@ends_with||= ->(slice) { F.equal.(slice) * drop_except.(length.(slice)) }
831
+ end
832
+
833
+ def intersperse
834
+ @@intersperse||= ->(x, xs) { rest * flatmap.(->(y) { [x, y].to_stream }) << xs.to_stream }
835
+ end
836
+
837
+ def contains?
838
+ @@contains_p||= ->(el) { F.not * F.equal.(Nothing) * find_where.(equals.(el)) }
839
+ end
840
+
841
+ def does_not_contain?
842
+ @@does_not_contain_p||= ->(el) { F.equal.(Nothing) * find_where.(equals.(el)) }
843
+ end
844
+
845
+ def contains_slice?
846
+ @@contains_slice_p||= ->(slice) { any?.(starts_with.(slice)) * tails }
847
+ end
848
+
849
+ def partition_at
850
+ @@partition_at||= ->(n) { take.(n) + drop.(n) }
851
+ end
852
+
853
+ def last_index_of
854
+ @@last_index_of||= ->(x) { last_index_where.(F.equal.(x)) }
855
+ end
856
+
857
+ def first_index_of
858
+ @@first_index_of||= ->(x) { first_index_where.( F.equal.(x) ) }
859
+ end
860
+
861
+ def union
862
+ @@union||= ->(xs) {
863
+ ->(ys) {
864
+ to_stream * to_set << append.(xs, ys)
865
+ } * to_stream
866
+ } * to_stream
867
+ end
497
868
 
498
- Stream.new(next_fn, [[]] + streams)
869
+ def intersect
870
+ @@intersect||= ->(xs) {
871
+ ->(ys) {
872
+ to_stream << (to_set.(xs) & to_set.(ys))
873
+ } * to_stream
874
+ } * to_stream
875
+ end
876
+
877
+ def difference
878
+ @@difference||= ->(xs) {
879
+ ->(ys) {
880
+ to_remove = to_set.(ys)
881
+ filter.(->(x) { !ys.include?(x)}) << xs
882
+ } * to_stream
883
+ } * to_stream
884
+ end
885
+
886
+ def cartesian_product
887
+ @@cartesian_product||= ->(xs) {
888
+ ->(ys) {
889
+ flatmap.(->(x) { map.(->(y) { [x,y] }, ys) }, xs)
890
+ } * to_stream
891
+ } * to_stream
892
+ end
893
+
894
+ def unzip
895
+ @@unzip||= ->(xs) {
896
+ map.(first) + map.(last) << xs
897
+ } * to_stream
898
+ end
899
+
900
+ def window
901
+ @@window||= ->(n) {
902
+ map.(take.(n)) * suffixes
499
903
  }
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"
904
+ end
905
+
906
+ def subsequences
907
+ @@subsequences||= ->() { ## Using the applicative instance for <**>, which is ^ in Raskell
908
+ subs = ->(ys) { ys == empty ? wrap.(empty) : subs.(rest.(ys)) ^ [F.id, F.cons.(first.(ys))].to_stream }
909
+ }.() #wrap.(empty)
910
+ end
911
+ ## Using Control.Applicative
912
+ # subs [] = [[]]
913
+ # subs (@@x||=xs) = subs xs <**> [id, (x :)]
914
+ ## subsequences is useful for fuzzy sequence matching style algorithms a la command tab in sublime,
915
+ ### or figuring out if some melody or progressionis an elaboration of another (same thing), etc...
916
+ ## is there any way to do this with a left fold instead of a right one?
917
+
918
+
919
+ def continuous_subsequences
920
+ @@continuous_subsequences||= filter.(F.not * empty?) * flatmap.(prefixes) * suffixes
921
+ end
922
+ ## continuous subsequences is useful for exact inside sequence matching a la find in sublime
923
+
924
+ def quicksort
925
+ ->(xs) {
926
+ if empty?.(xs)
927
+ empty
928
+ else
929
+ pivot = head.(xs)
930
+ partitions = (F.map.(self.quicksort) * partition_by.(F.is_lte.(pivot)) << tail.(xs)).to_a
931
+ append.(partitions[0],cons.(pivot, partitions[1]))
550
932
  end
933
+ } * to_stream ### if only this wasn't infinitely recursing...
934
+ end
935
+
936
+ def group
937
+ @@group||= ->(xs) { group_by.(id) }
938
+ end
939
+
940
+ end
941
+
942
+ module NumericStreamLambdas
943
+ extend self
944
+
945
+ def range ## count from the first to the second by increments of one
946
+ @@range||= ->(begin_with, end_with) {
947
+ (if begin_with <= end_with
948
+ stream_next_fn = ->(n) { n > end_with ? [:done] : [:yield, n, Stream.new(stream_next_fn, n + 1)] }
949
+ Stream.new(stream_next_fn, begin_with)
950
+ else
951
+ stream_next_fn = ->(n) { n < end_with ? [:done] : [:yield, n, Stream.new(stream_next_fn, n - 1)] }
952
+ Stream.new(stream_next_fn, begin_with)
953
+ end)
551
954
  }
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
955
+ end
956
+
957
+ def naturals
958
+ @@naturals||= range.(1, infinity)
959
+ end
960
+
961
+ def maximum
962
+ @@maximum||= foldl.(max, negative_infinity)
963
+ end
964
+
965
+ def minimum
966
+ @@minimum||= foldl.(min, infinity)
967
+ end
968
+
969
+ def maximum_by
970
+ @@maximum_by||= ->(fn) { foldl.(->(max_so_far, el) { max_so_far == Nothing || fn.(el) > fn.(max_so_far) ? el : max_so_far}, Nothing) }
971
+ end
972
+
973
+ def minimum_by
974
+ @@minimum_by||= ->(fn) { foldl.(->(min_so_far, el) { min_so_far == Nothing || fn.(el) < fn.(min_so_far) ? el : min_so_far}, Nothing) }
975
+ end
976
+
977
+ def sum
978
+ @@sum||= foldl.(plus, 0)
979
+ end
980
+
981
+ def product
982
+ @@product||= foldl.(times, 1)
983
+ end
984
+
985
+ def mean
986
+ @@mean||= ->(l) { div_from.(*( (sum + length).(l) )) }
987
+ end ## this works because (sum + length).(l)== [sum.(l), length.(l)]
988
+
989
+ def sum_of_squares
990
+ @@sum_of_squares||= sum * map.(square)
991
+ end
992
+
993
+ ## this is a one-pass algorithm, but only an estimate
994
+ #sum_of_squares_of_differences_from_mean_iterative
995
+ ## - need length, sum, sum_of_squares, M1,M2,M3, deltas, etc... see @@https||=//en.wikipedia.org/wiki/Algorithms_for_calculating_variance
996
+ ## population_variance
997
+ ## sample_variance
998
+ #->(l) {
999
+ # len, sm, sm_sqrs = (length + sum + sum_of_squares).(l)
1000
+ #}
1001
+
1002
+ ## this is a two-pass algorithm
1003
+
1004
+ def sum_of_differences_from_estimated_mean_two_pass
1005
+ @@sum_of_differences_from_estimated_mean||= ->(xs) { sum * map.(square * sub_by.(mean.(xs))) << xs }
1006
+ end
567
1007
 
1008
+ ## one pass might involve a scanl for (length, sum, flip * const), which is then mapped across to produce (mean, difference_from_mean, square_difference_from_mean, M2, ....), which is then scanl'd to summarize in some way, doing it all in a single pass.... I wonder if grouping the data and then transposing, and concatenating, then running the same query against it after to see how the values change as a stability measure.
1009
+
1010
+ #so to produce quicksort - foldl across the stream producing a tree, where inserting each element takes worst-case log(n), then call to_stream, which to produce all elements takes o(n)
568
1011
 
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
1012
+
1013
+ end
1014
+
1015
+ module StreamDropAndTakeLambdas
1016
+ extend self
1017
+
1018
+ ## there are so many of these I pulled them into their own
1019
+ def drop
1020
+ @@drop||= ->(n) {
1021
+ raise("#{n} must be a positive number") if n < 0
1022
+ ->(stream) {
1023
+ next_fn = step.(->(state){
1024
+ next_item = state.last.next_item
1025
+ count = next_item.first == :skip || state.first == 0 ? state.first : state.first-1
1026
+ next_item == [:done] ? Nothing : [count, next_item.last]
1027
+ },
1028
+ ->(state) {
1029
+ count = state.first
1030
+ next_item = state.last.next_item
1031
+ next_item.first == :yield && count == 0 ? next_item[1] : Nothing
1032
+ })
1033
+ Stream.new(next_fn, [n, stream])
1034
+ } * to_stream
580
1035
  }
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) {
1036
+ end
608
1037
 
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
1038
+ def take
1039
+ @@take||= ->(n) {
1040
+ raise("#{n} must be a positive number") if n < 0
1041
+ ->(stream) {
1042
+ next_fn = step.(->(state){
1043
+ if state.first == 0
1044
+ Nothing
1045
+ else
1046
+ next_item = state.last.next_item
1047
+ count = next_item.first == :skip ? state.first : state.first-1
1048
+ next_item == [:done] ? Nothing : [count, next_item.last]
1049
+ end
1050
+ },
1051
+ ->(state) {
1052
+ next_item = state.last.next_item
1053
+ next_item.first == :yield ? next_item[1] : Nothing
1054
+ })
1055
+ Stream.new(next_fn, [n, stream])
1056
+ } * to_stream
1057
+ }
1058
+ end
624
1059
 
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
1060
+ def drop_except
1061
+ @@drop_except||= ->(n) {
1062
+ raise("#{n} must be a positive number") if n < 0
1063
+ ->(stream) {
1064
+ next_fn = cstep.(
1065
+ ->(state) {
1066
+ strm = state.last
1067
+ accumulated_items = state.first
1068
+ next_el = strm.next_item
1069
+ accumulated_items = (state.first.length < n ? state.first : state.first[1..-1]) + [next_el[1]] if next_el.first == :yield
1070
+ next_el == [:done] ? accumulated_items.to_stream : Stream.new(next_fn, [accumulated_items, next_el.last])
1071
+ },
1072
+ ->(state) { Nothing }
1073
+ )
1074
+ Stream.new(next_fn, [[], stream])
1075
+ } * to_stream
648
1076
  }
649
- Stream.new(next_fn, [u, stream])
650
- } * to_stream
1077
+ end
651
1078
 
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
1079
+ def take_while
1080
+ @@take_while||= ->(fn) {
1081
+ raise("take_while requires a function") unless fn.kind_of?(Proc)
1082
+ ->(stream) {
1083
+ next_fn = ->(state) {
1084
+ next_item = state.next_item
1085
+ tag = next_item.first
1086
+ val = next_item[1]
1087
+ next_stream = next_item.last
1088
+ if tag == :done || (tag == :yield && !fn.(val))
1089
+ [:done]
1090
+ elsif tag == :skip
1091
+ [:skip, Stream.new(next_fn, next_stream)]
1092
+ elsif tag == :yield
1093
+ [:yield, val, Stream.new(next_fn, next_stream)]
1094
+ else
1095
+ raise("#{next_item} is a malformed stream response!")
1096
+ end
1097
+ }
1098
+ Stream.new(next_fn, stream)
1099
+ } * to_stream
699
1100
  }
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
1101
+ end
1102
+
1103
+ def drop_while
1104
+ @@drop_while||= ->(fn) {
1105
+ raise("drop_while requires a function") unless fn.kind_of?(Proc)
1106
+ ->(stream) {
1107
+ next_fn = ->(state) {
1108
+ next_item = state.next_item
1109
+ tag = next_item.first
1110
+ val = next_item[1]
1111
+ next_strm = next_item.last
1112
+ if tag == :done
1113
+ [:done]
1114
+ elsif tag == :skip || (tag == :yield && fn.(val))
1115
+ [:skip, Stream.new(next_fn, next_strm)]
1116
+ elsif tag == :yield
1117
+ [:yield, val, next_strm]
1118
+ else
1119
+ raise("#{next_item} is a malformed stream response!")
1120
+ end
1121
+ }
1122
+ Stream.new(next_fn, stream)
1123
+ } * to_stream
735
1124
  }
736
- Stream.new(next_fn, [stream, Nothing])
737
- } * to_stream
1125
+ end
738
1126
 
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
1127
+ def take_until
1128
+ @@take_until||= ->(fn) {
1129
+ raise("take_while requires a function") unless fn.kind_of?(Proc)
1130
+ ->(stream) {
1131
+ next_fn = ->(state) {
1132
+ next_item = state.next_item
1133
+ tag = next_item.first
1134
+ val = next_item[1]
1135
+ next_stream = next_item.last
1136
+ if tag == :done || (tag == :yield && fn.(val))
1137
+ [:done]
1138
+ elsif tag == :skip
1139
+ [:skip, Stream.new(next_fn, next_stream)]
1140
+ elsif tag == :yield
1141
+ [:yield, val, Stream.new(next_fn, next_stream)]
1142
+ else
1143
+ raise("#{next_item} is a malformed stream response!")
1144
+ end
1145
+ }
1146
+ Stream.new(next_fn, stream)
1147
+ } * to_stream
768
1148
  }
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
-
1149
+ end
818
1150
 
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)]
1151
+ def drop_until
1152
+ @@drop_until||= ->(fn) {
1153
+ raise("drop_while requires a function") unless fn.kind_of?(Proc)
1154
+ ->(stream) {
1155
+ next_fn = ->(state) {
1156
+ next_item = state.next_item
1157
+ tag = next_item.first
1158
+ val = next_item[1]
1159
+ next_strm = next_item.last
1160
+ if tag == :done
1161
+ [:done]
1162
+ elsif tag == :skip || (tag == :yield && !fn.(val))
1163
+ [:skip, Stream.new(next_fn, next_strm)]
1164
+ elsif tag == :yield
1165
+ [:yield, val, next_strm]
1166
+ else
1167
+ raise("#{next_item} is a malformed stream response!")
1168
+ end
1169
+ }
1170
+ Stream.new(next_fn, stream)
1171
+ } * to_stream
1172
+ }
1173
+ end
1174
+ end
1175
+
1176
+ module ConverterLambdas
1177
+ extend self
1178
+
1179
+ def to_stream
1180
+ @@to_stream||= ->(xs) { xs.to_stream }
1181
+ end
1182
+
1183
+ def from_stream(*args)
1184
+ if args.length > 0
1185
+ FromStream.new().(*args)
830
1186
  else
831
- raise("#{next_item} is a malformed stream response!")
1187
+ FromStream.new()
832
1188
  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
1189
+ end
879
1190
 
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)
1191
+ def lines_from_file
1192
+ @@lines_from_file||= ->(filepath, options={}) {
1193
+ (options['separator'] ? IO.foreach(filepath, options['separator']) : IO.foreach(filepath) ).to_stream
1194
+ }
978
1195
  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
1196
 
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
1197
+ def to_array
1198
+ FromStream.new(Array)
1199
+ end
1004
1200
 
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
-
1201
+ def to_hash
1202
+ FromStream.new(Hash)
1203
+ end
1020
1204
 
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) }
1205
+ def to_set
1206
+ FromStream.new(Set)
1207
+ end
1208
+
1209
+ def to_a
1210
+ self.to_array
1211
+ end
1212
+
1213
+ def to_h
1214
+ self.to_hash
1215
+ end
1216
+ end
1056
1217
  end
1057
1218
 
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
1219
 
1077
- def self.last_index_of
1078
- @@last_index_of||= ->(x) { last_index_where.(F.equal.(x)) }
1079
- end
1220
+ ## module System
1221
+ class F
1222
+ extend Collections::ConverterLambdas
1223
+ extend Collections::ObjectLambdas
1224
+ extend Collections::ProcishLambdas
1225
+ extend Collections::BooleanLambdas
1226
+ extend Collections::NumericLambdas
1227
+ extend Collections::StreamDropAndTakeLambdas
1228
+ extend Collections::OneForOneStreamLambdas
1229
+ extend Collections::FoldableStreamLambdas
1230
+ extend Collections::HigherOrderStreamLambdas
1231
+ extend Collections::NumericStreamLambdas
1232
+ extend Collections::StreamLambdas
1080
1233
 
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
- end
1234
+ def self.app
1235
+ @@app||= ->(*fs) { apply.(fs.first, fs.drop(1)) }
1236
+ end
1134
1237
 
1135
- def self.bucket_by_and_summarize
1136
- @@bucket_by_and_summarize||= ->(group_fn, summary_fn) {
1137
- map.(summary_fn) * bucket_by.(group_fn)
1138
- }
1139
- end
1140
-
1141
- def self.window
1142
- @@window||= ->(n) {
1143
- map.(take.(n)) * suffixes
1144
- }
1145
- end
1146
-
1147
- def self.subsequences
1148
- @@subsequences||= ->() { ## Using the applicative instance for <**>, which is ^ in Raskell
1149
- subs = ->(ys) { ys == empty ? wrap.(empty) : subs.(rest.(ys)) ^ [F.id, F.cons.(first.(ys))].to_stream }
1150
- }.() #wrap.(empty)
1151
- end
1152
- ## Using Control.Applicative
1153
- # subs [] = [[]]
1154
- # subs (@@x||=xs) = subs xs <**> [id, (x :)]
1155
- ## subsequences is useful for fuzzy sequence matching style algorithms a la command tab in sublime,
1156
- ### or figuring out if some melody or progressionis an elaboration of another (same thing), etc...
1157
- ## is there any way to do this with a left fold instead of a right one?
1158
-
1159
-
1160
- def self.continuous_subsequences
1161
- @@continuous_subsequences||= filter.(F.not * empty?) * flatmap.(prefixes) * suffixes
1162
- end
1163
- ## continuous subsequences is useful for exact inside sequence matching a la find in sublime
1164
-
1165
- def self.quicksort
1166
- ->(xs) {
1167
- if empty?.(xs)
1168
- empty
1169
- else
1170
- pivot = head.(xs)
1171
- partitions = (F.map.(self.quicksort) * partition_by.(F.is_lte.(pivot)) << tail.(xs)).to_a
1172
- append.(partitions[0],cons.(pivot, partitions[1]))
1173
- end
1174
- } * to_stream ### if only this wasn't infinitely recursing...
1175
- end
1176
-
1177
- def self.group_by
1178
- @@group_by||= ->(fn) {
1179
- next_fn = ->(state) {
1180
- strm = state.last
1181
- group = state.first
1182
- next_item = strm.next_item
1183
- tag = next_item.first
1184
- val = next_item[1]
1185
- next_stream = next_item.last
1186
- if tag == :done && group == []
1187
- [:done]
1188
- elsif tag == :done
1189
- [:yield, group, empty]
1190
- elsif tag == :skip
1191
- [:skip, Stream.new(next_fn, [group, next_stream])]
1192
- elsif tag == :yield && (group.length == 0 || fn.(val) == fn.(group.last))
1193
- [:skip, Stream.new(next_fn, [group + [val], next_stream])]
1194
- elsif tag == :yield
1195
- [:yield, group, Stream.new([[], next_stream])]
1196
- else
1197
- raise "#{next_item} is a malformed stream response!"
1198
- end
1199
- }
1200
- Stream.new(next_fn, [[], state])
1201
- } * to_stream
1238
+ def self.fold
1239
+ @@fold||= ->(fn, u) { final * scanl.(fn, u) }
1240
+ end
1241
+
1202
1242
  end
1243
+ end
1203
1244
 
1204
- def self.lines_from_file
1205
- @@lines_from_file||= ->(filepath, options={}) {
1206
- (options['separator'] ? IO.foreach(filepath, options['separator']) : IO.foreach(filepath) ).to_stream
1207
- }
1208
- end
1209
1245
 
1210
- def self.group
1211
- @@group||= ->(xs) { group_by.(id) }
1212
- end
1213
- end
1214
- #std
1246
+ class F < System::F;end;
1215
1247
 
1216
1248
  class Stream
1217
1249
 
@@ -1232,38 +1264,6 @@ class Stream
1232
1264
 
1233
1265
  end
1234
1266
 
1235
- =begin ## ruby doesn't allow you to override the return value on []=, which means we'd have to destructively alter this Stream
1236
- ## 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%?
1237
- def []=(index, item)
1238
- next_fn = ->(state) {
1239
- i = state.first
1240
- strm = state.last
1241
- if
1242
- [:yield, item, strm.next_item.last]
1243
- else
1244
- next_item = strm.next_item
1245
- tag = next_item.first
1246
- val = next_item[1]
1247
- next_stream = next_item.last
1248
- if tag == :done && i < index
1249
- [:skip, F.snoc(item, Array.new(index - i-1, Nothing).to_stream)]
1250
- elsif tag == :skip
1251
- [:skip, Stream.new(next_fn, next_stream)]
1252
- elsif tag == :yield && i == index
1253
- [:yield, item, next_stream]
1254
- elsif tag == :yield
1255
- [:yield, val, Stream.new(next_fn, next_stream)]
1256
- else
1257
- raise "#{next_item} is a malformed stream response"
1258
- end
1259
- end
1260
- }
1261
- state = [0, self.deep_clone]
1262
- self.next_item_function = next_fn
1263
- self.state = state
1264
- end
1265
- =end
1266
-
1267
1267
  def first
1268
1268
  F.first.(self)
1269
1269
  end
@@ -1332,7 +1332,7 @@ end
1332
1332
  class Array
1333
1333
 
1334
1334
  ## Applicative <**>
1335
- ## [1,2,3] ** [id, double]
1335
+ ## [1,2,3] ^ [id, double] == [1,2,3].flatmap([id, double])
1336
1336
  ## [1,2,2,4,3,6]
1337
1337
  def ^(arr, is_cartesian=false)
1338
1338
  is_cartesian || !arr.any?{|x| x.kind_of? Proc } ? self.cartesian_product(arr) : F.flatmap.(->(x) { arr.to_stream.(x) }).(self).to_a
@@ -1345,7 +1345,7 @@ class Array
1345
1345
  end
1346
1346
 
1347
1347
  ## zip or Applicative <*> depending on if there any function values in the array/stream
1348
- #[id, double] * [1,2,3]
1348
+ #[id, double] ** [1,2,3]
1349
1349
  #[1,2,3,2,4,6]
1350
1350
  def **(arr, is_zip=false)
1351
1351
  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