rb-kgy-fp 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1d187603140145361013f2277fb3d89ec9a2a49373a5b1d2d0839e48f9b53f48
4
+ data.tar.gz: 1eb4b34145b0ac7ce815cd4c4d55e4f82bb10b3469705ff4dd28fcc5e80a00f0
5
+ SHA512:
6
+ metadata.gz: b4bfb2827314527f15092992d70c25332c703660a85c14f5038a0179667190c0773a9d0341a51ed78491a4119ab3fbc117bf954c2056090874360a128582ff75
7
+ data.tar.gz: 1ddb718352d5eaf953c21280573b1086a00da7b0d627d46c1130f66f6db995df7985928f2c85f23115ec672b16553421b16c493ecff5554609e0e9e94c49acf6
@@ -0,0 +1,351 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lib/special'
4
+
5
+ PH = Special::PH
6
+ OPT = Special::OPT
7
+
8
+ module CurryFun
9
+ def self.eq?(t, u = PH)
10
+ if u == PH
11
+ ->(u) { eq? t, u }
12
+ else
13
+ t == u
14
+ end
15
+ end
16
+
17
+ def self.ne?(t, u = PH)
18
+ if u == PH
19
+ ->(u) { ne? t, u }
20
+ else
21
+ t != u
22
+ end
23
+ end
24
+
25
+ def self.gt?(t, u = PH)
26
+ if u == PH
27
+ ->(u) { gt? t, u }
28
+ elsif t.respond_to? :>
29
+ t > u
30
+ else
31
+ (t <=> u) == 1
32
+ end
33
+ end
34
+
35
+ def self.ge?(t, u = PH)
36
+ if u == PH
37
+ ->(u) { ge? t, u }
38
+ elsif t.respond_to? :>=
39
+ t >= u
40
+ else
41
+ (t <=> u) >= 0
42
+ end
43
+ end
44
+
45
+ def self.lt?(t, u = PH)
46
+ if u == PH
47
+ ->(u) { lt? t, u }
48
+ elsif t.respond_to? :<
49
+ t < u
50
+ else
51
+ (t <=> u) == -1
52
+ end
53
+ end
54
+
55
+ def self.le?(t, u = PH)
56
+ if u == PH
57
+ ->(u) { le? t, u }
58
+ elsif t.respond_to? :<=
59
+ t <= u
60
+ else
61
+ (t <=> u) <= 0
62
+ end
63
+ end
64
+
65
+ def self.const(a, _ = PH)
66
+ if _ == PH
67
+ ->(_) { a }
68
+ else
69
+ a
70
+ end
71
+ end
72
+
73
+ def self.pipe(*fns)
74
+ ->(arg) { fns.reduce(arg) { |acc, fn| fn.(acc) } }
75
+ end
76
+
77
+ def self.compose(*fns)
78
+ ->(arg) { fns.reverse.reduce(arg) { |acc, fn| fn.(acc) } }
79
+ end
80
+
81
+ def self.not? & fn
82
+ ->(*args, **kwargs) { !fn.(*args, **kwargs) }
83
+ end
84
+
85
+ def self.nil_or fallback, value = PH
86
+ if value == PH
87
+ ->(value) { nil_or fallback, value }
88
+ else
89
+ value.nil? ? fallback : value
90
+ end
91
+ end
92
+
93
+ def self.nil_or_else get_fallback: OPT, value: PH, &blk
94
+ if (!blk && get_fallback == OPT) || (blk && get_fallback.class == Proc)
95
+ raise ArgumentError.new "Either get_fallback or blk must be provided"
96
+ end
97
+ _fn = blk || get_fallback
98
+ if value == PH
99
+ ->(value) { nil_or_else get_fallback: _fn, value: value }
100
+ else
101
+ value.nil? ? _fn.() : value
102
+ end
103
+ end
104
+
105
+ def self.not_nil_or fallback, value = PH
106
+ if value == PH
107
+ ->(value) { not_nil_or fallback, value }
108
+ else
109
+ value.nil? ? value : fallback
110
+ end
111
+ end
112
+
113
+ def self.not_nil_or_else get_fallback: OPT, value: PH, &blk
114
+ if (!blk && get_fallback == OPT) || (blk && get_fallback.class == Proc)
115
+ raise ArgumentError.new "Either get_fallback or blk must be provided"
116
+ end
117
+ _fn = blk || get_fallback
118
+ if value == PH
119
+ ->(value) { not_nil_or_else get_fallback: _fn, value: value }
120
+ else
121
+ value.nil? ? value : _fn.()
122
+ end
123
+ end
124
+
125
+ def self.not_nil_map mapper: OPT, value: PH, &blk
126
+ if (!blk && mapper == OPT) || (blk && (mapper.class == Proc || mapper.class == Symbol))
127
+ raise ArgumentError.new "Either mapper or blk must be provided"
128
+ end
129
+ _fn = blk || (mapper.class == Proc ? mapper : ->(obj) { obj.method(mapper).() })
130
+ if value == PH
131
+ ->(value) { not_nil_map mapper: _fn, value: value }
132
+ else
133
+ value.nil? ? value : _fn.(value)
134
+ end
135
+ end
136
+
137
+ def self.add a, b = PH
138
+ if b == PH
139
+ ->(b) { add a, b }
140
+ else
141
+ a + b
142
+ end
143
+ end
144
+
145
+ def self.minus a, b = PH
146
+ if b == PH
147
+ ->(b) { minus a, b }
148
+ else
149
+ a - b
150
+ end
151
+ end
152
+
153
+ def self.mul a, b = PH
154
+ if b == PH
155
+ ->(b) { mul a, b }
156
+ else
157
+ a * b
158
+ end
159
+ end
160
+
161
+ def self.div a, b = PH
162
+ if b == PH
163
+ ->(b) { div a, b }
164
+ else
165
+ a / b
166
+ end
167
+ end
168
+
169
+ def self.mod a, b = PH
170
+ if b == PH
171
+ ->(b) { mod a, b }
172
+ else
173
+ a % b
174
+ end
175
+ end
176
+
177
+ def self.flip a, b = PH, &fn
178
+ if b == PH && !fn
179
+ ->(b = PH, &fn) { flip(a, b, &fn) }
180
+ elsif b == PH && fn
181
+ ->(b) { flip(a, b, &fn) }
182
+ elsif b != PH && !fn
183
+ ->(&fn) { flip(a, b, &fn) }
184
+ else
185
+ fn.(b, a)
186
+ end
187
+ end
188
+
189
+ def self.all? fn: OPT, args: PH, &blk
190
+ if (fn == OPT && !blk) || ((fn.class == Proc || fn.class == Symbol) && blk)
191
+ raise ArgumentError.new("Either fn or blk must be provided")
192
+ end
193
+ _fn = blk || (fn.class == Proc ? fn : ->(obj) { obj.method(fn).() })
194
+ if args == PH
195
+ ->(*args) { all?(fn: _fn, args: args) }
196
+ else
197
+ args.reduce(true) { |result, arg| result && _fn.(arg) }
198
+ end
199
+ end
200
+
201
+ def self.any? fn: OPT, args: PH, &blk
202
+ if (fn == OPT && !blk) || ((fn.class == Proc || fn.class == Symbol) && blk)
203
+ raise ArgumentError.new("Either fn or blk must be provided")
204
+ end
205
+ _fn = blk || (fn.class == Proc ? fn : ->(obj) { obj.method(fn).() })
206
+ if args == PH
207
+ ->(*args) { any?(fn: _fn, args: args) }
208
+ else
209
+ args.reduce(false) { |result, arg| result || _fn.(arg) }
210
+ end
211
+ end
212
+
213
+ def self.and? a, b = PH
214
+ if b == PH
215
+ ->(b) { and?(a, b) }
216
+ else
217
+ a && b
218
+ end
219
+ end
220
+
221
+ def self.or? a, b = PH
222
+ if b == PH
223
+ ->(b) { or?(a, b) }
224
+ else
225
+ a || b
226
+ end
227
+ end
228
+
229
+ def self.xor? a, b = PH
230
+ if b == PH
231
+ ->(b) { xor? a, b }
232
+ else
233
+ (!a && b) || (a && !b)
234
+ end
235
+ end
236
+
237
+ def self.clamp lower, upper = PH, value = PH
238
+ if upper == PH
239
+ ->(upper = PH, value = PH) { clamp lower, upper, value }
240
+ elsif value == PH
241
+ ->(value) { clamp lower, upper, value }
242
+ else
243
+ if lower > value
244
+ lower
245
+ elsif upper < value
246
+ upper
247
+ else
248
+ value
249
+ end
250
+ end
251
+ end
252
+
253
+ def self.cond cond_mappers
254
+ -> (*args, **kwargs) {
255
+ return nil if args.length == 0 && kwargs.size == 0
256
+ cond_mappers.each do |fns|
257
+ fns => [cond, mapper]
258
+ return mapper.(*args, **kwargs) if cond.(*args, **kwargs)
259
+ end
260
+ nil
261
+ }
262
+ end
263
+
264
+ def self.desc(&comparator)
265
+ -> (values) {
266
+ if values.class == Hash
267
+ Hash[values.sort_by { |k, v| comparator.(k, v) }.reverse]
268
+ elsif values.class == Array
269
+ values.sort_by { |v| comparator.(v) }.reverse
270
+ end
271
+ }
272
+ end
273
+
274
+ def self.asc(&comparator)
275
+ -> (values) {
276
+ if values.class == Hash
277
+ Hash[values.sort_by { |k, v| comparator.(k, v) }]
278
+ elsif values.class == Array
279
+ values.sort_by { |v| comparator.(v) }
280
+ end
281
+ }
282
+ end
283
+
284
+ def self.diff obj1, obj2 = PH
285
+ if obj2 == PH
286
+ ->(obj2) { diff obj1, obj2 }
287
+ else
288
+ get_diff = ->(arr1, arr2) {
289
+ arr1.size > arr2.size ? arr1 - arr2 : arr2 - arr1
290
+ }
291
+ if obj1.class != obj2.class
292
+ raise ArgumentError.new "obj1 is not same type with obj2"
293
+ elsif obj1.class == Hash
294
+ diff = get_diff.(obj1.to_a, obj2.to_a)
295
+ Hash[*diff.flatten]
296
+ else
297
+ get_diff.(obj1, obj2)
298
+ end
299
+ end
300
+ end
301
+
302
+ def self.intersect obj1, obj2 = PH
303
+ if obj2 == PH
304
+ ->(obj2) { intersect obj1, obj2 }
305
+ else
306
+ get_inte = ->(arr1, arr2) {
307
+ arr1.size > arr2.size ? arr1 - (arr1 - arr2) : arr2 - (arr2 - arr1)
308
+ }
309
+ if obj1.class != obj2.class
310
+ raise ArgumentError.new "obj1 is not same type with obj2"
311
+ elsif obj1.class == Hash
312
+ inte = get_inte.(obj1.to_a, obj2.to_a)
313
+ Hash[*inte.flatten]
314
+ else
315
+ get_inte.(obj1, obj2)
316
+ end
317
+ end
318
+ end
319
+
320
+ def self.non_intersect obj1, obj2 = PH
321
+ if obj2 == PH
322
+ ->(obj2) { non_intersect obj1, obj2 }
323
+ else
324
+ if obj1.class != obj2.class
325
+ raise ArgumentError.new "obj1 is not same type with obj2"
326
+ elsif obj1.class == Hash
327
+ left = obj1.to_a - obj2.to_a
328
+ right = obj2.to_a - obj1.to_a
329
+ Hash[*left.flatten, *right.flatten]
330
+ else
331
+ left = obj1 - obj2
332
+ right = obj2 - obj1
333
+ (left + right).uniq
334
+ end
335
+ end
336
+ end
337
+
338
+ def self.union obj1, obj2 = PH
339
+ if obj2 == PH
340
+ ->(obj2) { union obj1, obj2 }
341
+ else
342
+ if obj1.class != obj2.class
343
+ raise ArgumentError.new "obj1 is not same type with obj2"
344
+ elsif obj1.class == Hash
345
+ obj1.merge(obj2)
346
+ else
347
+ (obj1 + obj2).uniq
348
+ end
349
+ end
350
+ end
351
+ end
@@ -0,0 +1,378 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fun
4
+ def self.eq?(a, b)
5
+ a == b
6
+ end
7
+
8
+ def self.ne?(a, b)
9
+ a != b
10
+ end
11
+
12
+ def self.gt?(a, b)
13
+ if a.respond_to?(:>)
14
+ a > b
15
+ else
16
+ (a <=> b) == 1
17
+ end
18
+ end
19
+
20
+ def self.ge?(a, b)
21
+ if a.respond_to?(:>=)
22
+ a >= b
23
+ else
24
+ (a <=> b) >= 0
25
+ end
26
+ end
27
+
28
+ def self.lt?(a, b)
29
+ if a.respond_to?(:<)
30
+ a < b
31
+ else
32
+ (a <=> b) == -1
33
+ end
34
+ end
35
+
36
+ def self.le?(a, b)
37
+ if a.respond_to?(:<=)
38
+ a <= b
39
+ else
40
+ (a <=> b) <= 0
41
+ end
42
+ end
43
+
44
+ def self.id t
45
+ t
46
+ end
47
+
48
+ def self.const(a, _)
49
+ a
50
+ end
51
+
52
+ def self.pipe(arg, *fns)
53
+ fns.reduce(arg) { |acc, fn| fn.(acc) }
54
+ end
55
+
56
+ def self.compose(arg, *fns)
57
+ fns.reverse.reduce(arg) { |acc, fn| fn.(acc) }
58
+ end
59
+
60
+ def self.not?(fn, *args, **kwargs)
61
+ !fn.(*args, **kwargs)
62
+ end
63
+
64
+ def self.nil_or(value, fallback)
65
+ value.nil? ? fallback : value
66
+ end
67
+
68
+ def self.nil_or_else(value, &get_fallback)
69
+ if value.nil?
70
+ get_fallback.()
71
+ else
72
+ value
73
+ end
74
+ end
75
+
76
+ def self.not_nil_or(value, fallback)
77
+ if !value.nil?
78
+ fallback
79
+ else
80
+ value
81
+ end
82
+ end
83
+
84
+ def self.not_nil_or_else(value, &get_fallback)
85
+ if !value.nil?
86
+ get_fallback.()
87
+ else
88
+ value
89
+ end
90
+ end
91
+
92
+ def self.not_nil_map(value, &mapper)
93
+ value.nil? ? value : mapper.(value)
94
+ end
95
+
96
+ def self.add(a, b)
97
+ a + b
98
+ end
99
+
100
+ def self.minus(a, b)
101
+ a - b
102
+ end
103
+
104
+ def self.mul(a, b)
105
+ a * b
106
+ end
107
+
108
+ def self.div(a, b)
109
+ a / b
110
+ end
111
+
112
+ def self.mod(a, b)
113
+ a % b
114
+ end
115
+
116
+ def self.flip(b, a, &fn)
117
+ fn.(a, b)
118
+ end
119
+
120
+ def self.all?(fst, *snd)
121
+ if fst.class == Proc
122
+ snd.all?(&fst)
123
+ else
124
+ snd.reduce(true) { |result, fn| result && fn.(fst) }
125
+ end
126
+ end
127
+
128
+ def self.any?(fst, *snd)
129
+ if fst.class == Proc
130
+ snd.all?(&fst)
131
+ else
132
+ snd.reduce(false) { |result, fn| result || fn.(fst) }
133
+ end
134
+ end
135
+
136
+ def self.clamp(lower, upper, value)
137
+ if lower > value
138
+ lower
139
+ elsif upper < value
140
+ upper
141
+ else
142
+ value
143
+ end
144
+ end
145
+
146
+ def self.cond(cond_mappers, *args, **kwargs)
147
+ return nil if args.length == 0 && kwargs.size == 0
148
+ cond_mappers.each { |fns|
149
+ fns => [cond, mapper]
150
+ return mapper.(*args, **kwargs) if cond.(*args, **kwargs)
151
+ }
152
+ nil
153
+ end
154
+
155
+ def self.curry(&fn)
156
+ require "special"
157
+
158
+ req = 1 << 0
159
+ opt = 1 << 1
160
+ rest = 1 << 2
161
+ kreq = 1 << 3
162
+ kopt = 1 << 4
163
+ krest = 1 << 5
164
+ block = 1 << 6
165
+
166
+ core = ->(this, fn, c_params = [], c_remain_param_count = 0) do
167
+ ->(*args, **kwargs, &proc) do
168
+ cp_c_params = Marshal.load(Marshal.dump(c_params)) # use serialization to ensure whole operation is pure
169
+ cp_c_remain_param_count = c_remain_param_count
170
+ arg_idx = 0
171
+ _kwargs = { **kwargs }
172
+
173
+ (0...cp_c_params.length).each { |i|
174
+ param = cp_c_params[i]
175
+ filled = param[:value] != Special::PH && param[:value] != Special::OPT
176
+
177
+ if (param[:type] & (req | opt)) != 0 && !filled
178
+ param[:value] = args[arg_idx]
179
+ arg_idx += 1
180
+ cp_c_remain_param_count -= 1 if param[:type] == req
181
+ end
182
+
183
+ if (param[:type] & (kreq | kopt) != 0) && !filled && _kwargs[param[:name]] != nil
184
+ param[:value] = _kwargs.delete(param[:name])
185
+ cp_c_remain_param_count -= 1 if param[:type] == kreq
186
+ end
187
+
188
+ if param[:type] == block && !filled && proc
189
+ param[:value] = proc
190
+ cp_c_remain_param_count -= 1
191
+ end
192
+ }
193
+
194
+ if args.length >= arg_idx + 1 && cp_c_params.any? { |p| p[:type] == rest }
195
+ cp_c_params.find { |p| p[:type] == rest }[:value] = args[arg_idx, args.length]
196
+ end
197
+
198
+ if _kwargs.length > 0 && cp_c_params.any? { |p| p[:type] == krest }
199
+ cp_c_params.find { |p| p[:type] == krest }[:value] = _kwargs
200
+ end
201
+
202
+ if cp_c_remain_param_count == 0
203
+ _params = []
204
+ _kparams = {}
205
+ _proc = nil
206
+ cp_c_params.each do |param|
207
+ case param[:type]
208
+ when req, opt
209
+ _params << param[:value] if param[:value] != Special::OPT && param[:value] != Special::PH
210
+ when kreq, kopt
211
+ _kparams[param[:name]] = param[:value] if param[:value] != Special::OPT && param[:value] != Special::PH
212
+ when rest
213
+ _params.push(*param[:value])
214
+ when krest
215
+ _kparams.update(param[:value])
216
+ when proc
217
+ _proc = param[:value]
218
+ end
219
+ end
220
+ if _proc
221
+ fn.(*_params, **_kparams, &_proc)
222
+ else
223
+ fn.(*_params, **_kparams)
224
+ end
225
+ else
226
+ this.(this, fn, cp_c_params, cp_c_remain_param_count)
227
+ end
228
+ end
229
+ end
230
+
231
+ params = []
232
+ remain_param_count = 0
233
+
234
+ # check params
235
+ fn.parameters.each do |detail|
236
+ detail => [type, name]
237
+ case type
238
+ when :req
239
+ params << { name: name, value: Special::PH, type: req }
240
+ remain_param_count += 1
241
+ when :opt
242
+ params << { name: name, value: Special::OPT, type: opt }
243
+ when :rest
244
+ params << { name: name, type: rest }
245
+ when :keyreq
246
+ params << { name: name, value: Special::PH, type: kreq }
247
+ remain_param_count += 1
248
+ when :key
249
+ params << { name: name, value: Special::OPT, type: kopt }
250
+ when :keyrest
251
+ params << { name: name, type: krest }
252
+ when :block
253
+ params << { name: name, value: Special::PH, type: block }
254
+ remain_param_count += 1
255
+ end
256
+ end
257
+
258
+ core.(core, fn, params, remain_param_count)
259
+ end
260
+
261
+ def self.dec n
262
+ n - 1
263
+ end
264
+
265
+ def self.inc n
266
+ n + 1
267
+ end
268
+
269
+ def self.desc(values, &comparator)
270
+ if values.class == Hash
271
+ Hash[values.sort_by { |k, v| comparator.(k, v) }.reverse]
272
+ elsif values.class == Array
273
+ values.sort_by { |v| comparator.(v) }.reverse
274
+ end
275
+ end
276
+
277
+ def self.asc(values, &comparator)
278
+ if values.class == Hash
279
+ Hash[values.sort_by { |k, v| comparator.(k, v) }]
280
+ elsif values.class == Array
281
+ values.sort_by { |v| comparator.(v) }
282
+ end
283
+ end
284
+
285
+ def self.to_sym s
286
+ s.to_sym
287
+ end
288
+
289
+ def self.diff(obj1, obj2)
290
+ get_diff = ->(arr1, arr2) {
291
+ arr1.size > arr2.size ? arr1 - arr2 : arr2 - arr1
292
+ }
293
+ if obj1.class != obj2.class
294
+ raise ArgumentError.new "obj1 is not same type with obj2"
295
+ elsif obj1.class == Hash
296
+ diff = get_diff.(obj1.to_a, obj2.to_a)
297
+ Hash[*diff.flatten]
298
+ else
299
+ get_diff.(obj1, obj2)
300
+ end
301
+ end
302
+
303
+ def self.intersect(obj1, obj2)
304
+ get_inte = ->(arr1, arr2) {
305
+ arr1.size > arr2.size ? arr1 - (arr1 - arr2) : arr2 - (arr2 - arr1)
306
+ }
307
+ if obj1.class != obj2.class
308
+ raise ArgumentError.new "obj1 is not same type with obj2"
309
+ elsif obj1.class == Hash
310
+ inte = get_inte.(obj1.to_a, obj2.to_a)
311
+ Hash[*inte.flatten]
312
+ else
313
+ get_inte.(obj1, obj2)
314
+ end
315
+ end
316
+
317
+ def self.non_intersect(obj1, obj2)
318
+ if obj1.class != obj2.class
319
+ raise ArgumentError.new "obj1 is not same type with obj2"
320
+ elsif obj1.class == Hash
321
+ left = obj1.to_a - obj2.to_a
322
+ right = obj2.to_a - obj1.to_a
323
+ Hash[*left.flatten, *right.flatten]
324
+ else
325
+ left = obj1 - obj2
326
+ right = obj2 - obj1
327
+ (left + right).uniq
328
+ end
329
+ end
330
+
331
+ def self.union(obj1, obj2)
332
+ if obj1.class != obj2.class
333
+ raise ArgumentError.new "obj1 is not same type with obj2"
334
+ elsif obj1.class == Hash
335
+ obj1.merge(obj2)
336
+ else
337
+ (obj1 + obj2).uniq
338
+ end
339
+ end
340
+
341
+ def self.empty obj
342
+ case obj.class.to_s
343
+ when 'Hash'
344
+ {}
345
+ when 'Array'
346
+ []
347
+ when 'String'
348
+ ''
349
+ else
350
+ nil
351
+ end
352
+ end
353
+
354
+ def self.mean * ns
355
+ ns.reduce(:+) / ns.length
356
+ end
357
+
358
+ def self.median * ns
359
+ ns.sort[(ns.length / 2).floor]
360
+ end
361
+
362
+ def self.memorize_with(get_key, &action)
363
+ cache = {}
364
+ ->(*args, **kwargs) do
365
+ key = get_key.(*args, **kwargs).to_sym
366
+ cache[key] = action.(*args, **kwargs) unless cache[key]
367
+ cache[key]
368
+ end
369
+ end
370
+
371
+ def self.negate n
372
+ -n
373
+ end
374
+
375
+ def self.xor? a, b
376
+ (a && !b) || (!a && b)
377
+ end
378
+ end