rb-kgy-fp 1.0.0

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