egison 0.2.1 → 0.3.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 +4 -4
- data/README.md +35 -0
- data/THANKS.md +5 -0
- data/lib/egison/core.rb +99 -3
- data/lib/egison/lazyarray.rb +166 -0
- data/lib/egison/matcher-core.rb +35 -0
- data/lib/egison/matcher.rb +63 -0
- data/lib/egison/version.rb +1 -1
- data/sample/stream.rb +20 -0
- data/spec/sample/stream_spec.rb +41 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74ce8492a345ad492c9acb9e16c7c8d351a6b327
|
4
|
+
data.tar.gz: 26f3f0aef845aaf21312713df5e418b724d4cbb0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84f1a8ef64f513ea072ae2c6153c5bc3fd8868f065af6b74209797a949fe3573e0318a34f3de9b610003d76ee6745f8961c17856ca560be87f11e7e8bc20283e
|
7
|
+
data.tar.gz: dd5c108d612a531bdde3b27ac1238af2ddd136259059eb9114f6f7af5304d140b24307119a485a45d37dfdbf26e5829d47b2538908b4b6909f349f1760d742c1
|
data/README.md
CHANGED
@@ -146,6 +146,22 @@ match_all([1, 2, 3, 2, 5]) do
|
|
146
146
|
end #=> [2,2]
|
147
147
|
```
|
148
148
|
|
149
|
+
### Pattern Matching against Stream (Infinite List)
|
150
|
+
|
151
|
+
We can do pattern-matching against streams with the `match_stream` expression.
|
152
|
+
|
153
|
+
```
|
154
|
+
def nats
|
155
|
+
(1..Float::INFINITY)
|
156
|
+
end
|
157
|
+
|
158
|
+
match_stream(nats){ with(Multiset.(_m, _n, *_)) { [m, n] } }.take(10)
|
159
|
+
#=>[[1, 2], [1, 3], [2, 1], [1, 4], [2, 3], [3, 1], [1, 5], [2, 4], [3, 2], [4, 1]]
|
160
|
+
|
161
|
+
match_stream(nats){ with(Set.(_m, _n, *_)) { [m, n] } }.take(10)
|
162
|
+
#=>[[1, 1], [1, 2], [2, 1], [1, 3], [2, 2], [3, 1], [1, 4], [2, 3], [3, 2], [4, 1]]
|
163
|
+
```
|
164
|
+
|
149
165
|
## Demonstrations
|
150
166
|
|
151
167
|
### Combinations
|
@@ -210,6 +226,25 @@ p(poker_hands([["diamond", 4], ["club", 2], ["club", 5], ["heart", 1], ["diamond
|
|
210
226
|
p(poker_hands([["diamond", 4], ["club", 10], ["club", 5], ["heart", 1], ["diamond", 3]])) #=> "Nothing"
|
211
227
|
```
|
212
228
|
|
229
|
+
### Twin Primes
|
230
|
+
|
231
|
+
The following code enumerates all twin primes with pattern-matching!
|
232
|
+
I believe it is also a really exciting demonstration.
|
233
|
+
|
234
|
+
```
|
235
|
+
require 'egison'
|
236
|
+
require 'prime'
|
237
|
+
|
238
|
+
twin_primes = match_stream(Prime) {
|
239
|
+
with(List.(*_, _x, __("x + 2"), *_)) {
|
240
|
+
[x, x + 2]
|
241
|
+
}
|
242
|
+
}
|
243
|
+
|
244
|
+
p twin_primes.take(10)
|
245
|
+
#=>[[3, 5], [5, 7], [11, 13], [17, 19], [29, 31], [41, 43], [59, 61], [71, 73], [101, 103], [107, 109]]
|
246
|
+
```
|
247
|
+
|
213
248
|
You can find more demonstrations in the [`sample`](https://github.com/egison/egison-ruby/tree/master/sample) directory.
|
214
249
|
|
215
250
|
## About Egison
|
data/THANKS.md
ADDED
data/lib/egison/core.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'egison/version'
|
2
|
-
require 'continuation'
|
2
|
+
# require 'continuation'
|
3
|
+
require 'egison/lazyarray'
|
3
4
|
|
4
5
|
module PatternMatch
|
5
6
|
module Matchable
|
@@ -47,6 +48,39 @@ module PatternMatch
|
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
51
|
+
class MatchingStateStream
|
52
|
+
def initialize(pat, tgt)
|
53
|
+
@states = [MatchingState.new(pat, tgt)]
|
54
|
+
@processes = []
|
55
|
+
end
|
56
|
+
|
57
|
+
def match(&block)
|
58
|
+
state = @states.shift
|
59
|
+
@processes << Egison::LazyArray.new(state.process_stream)
|
60
|
+
until @states.empty? && @processes.empty?
|
61
|
+
unless @processes.empty?
|
62
|
+
process(@processes.shift, &block)
|
63
|
+
end
|
64
|
+
unless @states.empty?
|
65
|
+
state = @states.shift
|
66
|
+
process(Egison::LazyArray.new(state.process_stream), &block)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def process(process_iter, &block)
|
72
|
+
unless process_iter.empty?
|
73
|
+
@processes << process_iter
|
74
|
+
ret = process_iter.shift
|
75
|
+
if ret.atoms.empty?
|
76
|
+
block.(ret.bindings)
|
77
|
+
else
|
78
|
+
@states << ret
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
50
84
|
class MatchingState
|
51
85
|
attr_accessor :atoms, :bindings
|
52
86
|
|
@@ -65,6 +99,17 @@ module PatternMatch
|
|
65
99
|
new_state
|
66
100
|
end
|
67
101
|
end
|
102
|
+
|
103
|
+
def process_stream(&block)
|
104
|
+
return to_enum :process_stream unless block_given?
|
105
|
+
atom = @atoms.shift
|
106
|
+
atom.first.match_stream(atom.last, @bindings) do |new_atoms, new_bindings|
|
107
|
+
new_state = clone
|
108
|
+
new_state.atoms = new_atoms + new_state.atoms
|
109
|
+
new_state.bindings += new_bindings
|
110
|
+
block.(new_state)
|
111
|
+
end
|
112
|
+
end
|
68
113
|
end
|
69
114
|
|
70
115
|
class Pattern
|
@@ -76,6 +121,10 @@ module PatternMatch
|
|
76
121
|
def match(tgt, bindings)
|
77
122
|
end
|
78
123
|
|
124
|
+
def match_stream(tgt, bindings, &block)
|
125
|
+
match(tgt, bindings).each(&block)
|
126
|
+
end
|
127
|
+
|
79
128
|
def to_a
|
80
129
|
[PatternCollection.new(self)]
|
81
130
|
end
|
@@ -128,6 +177,32 @@ module PatternMatch
|
|
128
177
|
end
|
129
178
|
end
|
130
179
|
end
|
180
|
+
|
181
|
+
def match_stream(tgt, bindings, &block)
|
182
|
+
if subpatterns.empty?
|
183
|
+
if tgt.empty?
|
184
|
+
return block.([[], []])
|
185
|
+
end
|
186
|
+
else
|
187
|
+
subpatterns = @subpatterns.clone
|
188
|
+
px = subpatterns.shift
|
189
|
+
if px.quantified
|
190
|
+
if subpatterns.empty?
|
191
|
+
block.([[[px.pattern, tgt]], []])
|
192
|
+
else
|
193
|
+
@matcher.unjoin_stream(tgt) do |xs, ys|
|
194
|
+
block.([[px.pattern, xs], [PatternWithMatcher.new(@matcher, *subpatterns), ys]], [])
|
195
|
+
end
|
196
|
+
end
|
197
|
+
else
|
198
|
+
unless tgt.empty?
|
199
|
+
@matcher.uncons_stream(tgt) do |x, xs|
|
200
|
+
block.([[px, x], [PatternWithMatcher.new(@matcher, *subpatterns), xs]], [])
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
131
206
|
end
|
132
207
|
|
133
208
|
class Wildcard < PatternElement
|
@@ -337,6 +412,20 @@ module PatternMatch
|
|
337
412
|
end
|
338
413
|
end
|
339
414
|
|
415
|
+
class EnvE < Env
|
416
|
+
def with(pat, &block)
|
417
|
+
ctx = @ctx
|
418
|
+
tgt = @tgt
|
419
|
+
mstack = MatchingStateStream.new(pat,tgt)
|
420
|
+
::Enumerator.new do |y|
|
421
|
+
mstack.match do |bindings|
|
422
|
+
y << with_bindings(ctx, bindings, &block)
|
423
|
+
end
|
424
|
+
end
|
425
|
+
rescue PatternNotMatch
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
340
429
|
class PatternNotMatch < Exception; end
|
341
430
|
class PatternMatchError < StandardError; end
|
342
431
|
class NoMatchingPatternError < PatternMatchError; end
|
@@ -351,7 +440,7 @@ module PatternMatch
|
|
351
440
|
private_constant c
|
352
441
|
end
|
353
442
|
end
|
354
|
-
private_constant :Env, :Env2
|
443
|
+
private_constant :Env, :Env2, :EnvE
|
355
444
|
end
|
356
445
|
end
|
357
446
|
|
@@ -363,6 +452,14 @@ module Kernel
|
|
363
452
|
env.instance_eval(&block)
|
364
453
|
end
|
365
454
|
|
455
|
+
def match_stream(tgt, &block)
|
456
|
+
if !(tgt.kind_of?(Array) || tgt.kind_of?(Egison::LazyArray))
|
457
|
+
tgt = Egison::LazyArray.new(tgt)
|
458
|
+
end
|
459
|
+
env = PatternMatch.const_get(:EnvE).new(self, tgt)
|
460
|
+
env.instance_eval(&block)
|
461
|
+
end
|
462
|
+
|
366
463
|
def match(tgt, &block)
|
367
464
|
env = PatternMatch.const_get(:Env2).new(self, tgt)
|
368
465
|
catch(:exit_match) do
|
@@ -372,4 +469,3 @@ module Kernel
|
|
372
469
|
|
373
470
|
alias match_single match
|
374
471
|
end
|
375
|
-
|
@@ -0,0 +1,166 @@
|
|
1
|
+
module Egison
|
2
|
+
class LazyArray
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
class OrgEnum
|
6
|
+
def initialize(org_enum)
|
7
|
+
@src_enums = []
|
8
|
+
if org_enum.kind_of?(::Array)
|
9
|
+
@org_enum = [].to_enum # DUMMY
|
10
|
+
@cache = org_enum
|
11
|
+
@index = -1
|
12
|
+
@terminated = true
|
13
|
+
else
|
14
|
+
@org_enum = org_enum.to_enum
|
15
|
+
@cache = []
|
16
|
+
@index = -1
|
17
|
+
@terminated = false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def next
|
22
|
+
index = @index += 1
|
23
|
+
return @cache[index] if @cache.size > index
|
24
|
+
raise StopIteration.new('iteration reached an end') if @terminated
|
25
|
+
el = org_enum_next
|
26
|
+
@cache << el
|
27
|
+
el
|
28
|
+
rescue StopIteration => ex
|
29
|
+
@index -= 1
|
30
|
+
raise ex
|
31
|
+
end
|
32
|
+
|
33
|
+
def rewind(index=0)
|
34
|
+
@index = index - 1
|
35
|
+
end
|
36
|
+
|
37
|
+
def clone
|
38
|
+
obj = super
|
39
|
+
obj.instance_eval do
|
40
|
+
@src_enums = @src_enums.clone
|
41
|
+
end
|
42
|
+
obj
|
43
|
+
end
|
44
|
+
|
45
|
+
def concat other
|
46
|
+
if @terminated && other.kind_of?(::Array)
|
47
|
+
@cache.concat(other)
|
48
|
+
else
|
49
|
+
@src_enums.push(other)
|
50
|
+
@terminated = false
|
51
|
+
end
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def org_enum_next
|
57
|
+
el = nil
|
58
|
+
while el.nil?
|
59
|
+
begin
|
60
|
+
el = @org_enum.next
|
61
|
+
rescue StopIteration => ex
|
62
|
+
if @src_enums.empty?
|
63
|
+
@terminated = true
|
64
|
+
raise ex
|
65
|
+
end
|
66
|
+
@org_enum = @src_enums.shift.to_enum
|
67
|
+
@cache = @cache.clone
|
68
|
+
end
|
69
|
+
end
|
70
|
+
el
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private_constant :OrgEnum if respond_to?(:private_constant)
|
75
|
+
|
76
|
+
def initialize(org_enum)
|
77
|
+
@org_enum = OrgEnum.new(org_enum)
|
78
|
+
@cache = []
|
79
|
+
@terminated = false
|
80
|
+
end
|
81
|
+
|
82
|
+
def each(&block)
|
83
|
+
return to_enum unless block_given?
|
84
|
+
@cache.each(&block)
|
85
|
+
return if @terminated
|
86
|
+
while true # StopIteration will NOT be raised if `loop do ... end`
|
87
|
+
el = @org_enum.next
|
88
|
+
@cache.push(el)
|
89
|
+
block.(el)
|
90
|
+
end
|
91
|
+
rescue StopIteration => ex
|
92
|
+
@terminated = true
|
93
|
+
end
|
94
|
+
|
95
|
+
def shift
|
96
|
+
if @cache.size > 0
|
97
|
+
@cache.shift
|
98
|
+
elsif @terminated
|
99
|
+
nil
|
100
|
+
else
|
101
|
+
begin
|
102
|
+
@org_enum.next
|
103
|
+
rescue StopIteration => ex
|
104
|
+
@terminated = true
|
105
|
+
nil
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def unshift(*obj)
|
111
|
+
@cache.unshift(*obj)
|
112
|
+
self
|
113
|
+
end
|
114
|
+
|
115
|
+
def empty?
|
116
|
+
return false unless @cache.empty?
|
117
|
+
return true if @terminated
|
118
|
+
begin
|
119
|
+
@cache << @org_enum.next
|
120
|
+
false
|
121
|
+
rescue StopIteration => ex
|
122
|
+
@terminated = true
|
123
|
+
true
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def size
|
128
|
+
@terminated ? @cache.size : nil
|
129
|
+
end
|
130
|
+
alias :length :size
|
131
|
+
|
132
|
+
def clone
|
133
|
+
obj = super
|
134
|
+
obj.instance_eval do
|
135
|
+
@org_enum = @org_enum.clone
|
136
|
+
@cache = @cache.clone
|
137
|
+
end
|
138
|
+
obj
|
139
|
+
end
|
140
|
+
alias :dup :clone
|
141
|
+
|
142
|
+
def concat other
|
143
|
+
@org_enum.concat(other)
|
144
|
+
@terminated = false
|
145
|
+
self
|
146
|
+
end
|
147
|
+
|
148
|
+
def + other
|
149
|
+
clone.concat(other)
|
150
|
+
end
|
151
|
+
|
152
|
+
def inspect
|
153
|
+
"\#<#{self.class.name}#{@terminated ? @cache.inspect : "[#{@cache.join(', ')}...]"}>"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
class ::Array
|
159
|
+
alias :org_plus_meth_esc_by_egison_lazyarray :+
|
160
|
+
def + other
|
161
|
+
if other.kind_of?(Egison::LazyArray)
|
162
|
+
return other.clone.unshift(*self)
|
163
|
+
end
|
164
|
+
org_plus_meth_esc_by_egison_lazyarray(other)
|
165
|
+
end
|
166
|
+
end
|
data/lib/egison/matcher-core.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'egison/core'
|
2
|
+
require 'egison/lazyarray'
|
2
3
|
|
3
4
|
class Class
|
4
5
|
include PatternMatch::Matchable
|
@@ -7,11 +8,20 @@ class Class
|
|
7
8
|
raise NotImplementedError, "need to define `#{__method__}'"
|
8
9
|
end
|
9
10
|
|
11
|
+
def uncons_stream(val, &block)
|
12
|
+
raise NotImplementedError, "need to define `#{__method__}'"
|
13
|
+
end
|
14
|
+
|
10
15
|
private
|
11
16
|
|
12
17
|
def accept_array_only(val)
|
13
18
|
raise PatternMatch::PatternNotMatch unless val.kind_of?(Array)
|
14
19
|
end
|
20
|
+
|
21
|
+
def test_conv_lazy_array(val)
|
22
|
+
raise PatternMatch::PatternNotMatch unless val.respond_to?(:each)
|
23
|
+
Egison::LazyArray.new(val)
|
24
|
+
end
|
15
25
|
end
|
16
26
|
|
17
27
|
class List
|
@@ -25,6 +35,15 @@ class << List
|
|
25
35
|
[[x, val2]]
|
26
36
|
end
|
27
37
|
|
38
|
+
def uncons_stream(val, &block)
|
39
|
+
if !(val.kind_of?(Array) || val.kind_of?(Egison::LazyArray))
|
40
|
+
val = test_conv_lazy_array(val)
|
41
|
+
end
|
42
|
+
val2 = val.clone
|
43
|
+
x = val2.shift
|
44
|
+
block.([x, val2])
|
45
|
+
end
|
46
|
+
|
28
47
|
def unjoin(val)
|
29
48
|
accept_array_only(val)
|
30
49
|
val2 = val.clone
|
@@ -39,4 +58,20 @@ class << List
|
|
39
58
|
end
|
40
59
|
rets
|
41
60
|
end
|
61
|
+
|
62
|
+
def unjoin_stream(val, &block)
|
63
|
+
if !(val.kind_of?(Array) || val.kind_of?(Egison::LazyArray))
|
64
|
+
val = test_conv_lazy_array(val)
|
65
|
+
end
|
66
|
+
val2 = val.clone
|
67
|
+
xs = []
|
68
|
+
ys = val2.clone
|
69
|
+
block.([xs, ys])
|
70
|
+
until val2.empty?
|
71
|
+
x = val2.shift
|
72
|
+
ys = val2.clone
|
73
|
+
xs += [x]
|
74
|
+
block.([xs, ys])
|
75
|
+
end
|
76
|
+
end
|
42
77
|
end
|
data/lib/egison/matcher.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'egison/core'
|
2
|
+
require 'egison/lazyarray'
|
2
3
|
require 'egison/matcher-core'
|
3
4
|
require 'set'
|
4
5
|
|
@@ -15,6 +16,18 @@ class << Multiset
|
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
19
|
+
def uncons_stream(val, &block)
|
20
|
+
if !(val.kind_of?(Array) || val.kind_of?(Egison::LazyArray))
|
21
|
+
val = test_conv_lazy_array(val)
|
22
|
+
end
|
23
|
+
stream = match_stream(val) {
|
24
|
+
with(List.(*_hs, _x, *_ts)) do
|
25
|
+
[x, hs + ts]
|
26
|
+
end
|
27
|
+
}
|
28
|
+
stream.each(&block)
|
29
|
+
end
|
30
|
+
|
18
31
|
def unjoin(val)
|
19
32
|
accept_array_only(val)
|
20
33
|
val2 = val.clone
|
@@ -31,6 +44,26 @@ class << Multiset
|
|
31
44
|
rets
|
32
45
|
end
|
33
46
|
end
|
47
|
+
|
48
|
+
def unjoin_stream(val, &block)
|
49
|
+
if !(val.kind_of?(Array) || val.kind_of?(Egison::LazyArray))
|
50
|
+
val = test_conv_lazy_array(val)
|
51
|
+
end
|
52
|
+
val2 = val.clone
|
53
|
+
xs = []
|
54
|
+
ys = val2.clone
|
55
|
+
if val2.empty?
|
56
|
+
block.([xs, ys])
|
57
|
+
else
|
58
|
+
x = val2.shift
|
59
|
+
ys = val2.clone
|
60
|
+
rets_stream = Egison::LazyArray.new(to_enum(:unjoin_stream, ys))
|
61
|
+
# rets_stream.each{|xs2, ys2| block.([xs2, [x] + ys2])}
|
62
|
+
rets_stream.each{|xs2, ys2| block.([xs2, ys2.clone.unshift(x)])}
|
63
|
+
# rets_stream.each{|xs2, ys2| block.([[x] + xs2, ys2])}
|
64
|
+
rets_stream.each{|xs2, ys2| block.([xs2.clone.unshift(x), ys2])}
|
65
|
+
end
|
66
|
+
end
|
34
67
|
end
|
35
68
|
|
36
69
|
class << Set
|
@@ -43,6 +76,18 @@ class << Set
|
|
43
76
|
end
|
44
77
|
end
|
45
78
|
|
79
|
+
def uncons_stream(val, &block)
|
80
|
+
if !(val.kind_of?(Array) || val.kind_of?(Egison::LazyArray))
|
81
|
+
val = test_conv_lazy_array(val)
|
82
|
+
end
|
83
|
+
stream = match_stream(val) {
|
84
|
+
with(List.(*_, _x, *_)) do
|
85
|
+
[x, val]
|
86
|
+
end
|
87
|
+
}
|
88
|
+
stream.each(&block)
|
89
|
+
end
|
90
|
+
|
46
91
|
def unjoin(val)
|
47
92
|
accept_array_only(val)
|
48
93
|
val2 = val.clone
|
@@ -59,4 +104,22 @@ class << Set
|
|
59
104
|
rets
|
60
105
|
end
|
61
106
|
end
|
107
|
+
|
108
|
+
def unjoin_stream(val, &block)
|
109
|
+
if !(val.kind_of?(Array) || val.kind_of?(Egison::LazyArray))
|
110
|
+
val = test_conv_lazy_array(val)
|
111
|
+
end
|
112
|
+
val2 = val.clone
|
113
|
+
xs = []
|
114
|
+
ys = val2.clone
|
115
|
+
if val2.empty?
|
116
|
+
block.([xs, ys])
|
117
|
+
else
|
118
|
+
x = val2.shift
|
119
|
+
ys2 = val2.clone
|
120
|
+
rets_stream = Egison::LazyArray.new(to_enum(:unjoin_stream, ys2))
|
121
|
+
rets_stream.each{|xs2, _| block.([xs2, ys])}
|
122
|
+
rets_stream.each{|xs2, _| block.([xs2.clone.unshift(x), ys])}
|
123
|
+
end
|
124
|
+
end
|
62
125
|
end
|
data/lib/egison/version.rb
CHANGED
data/sample/stream.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'egison'
|
2
|
+
require 'prime'
|
3
|
+
|
4
|
+
p(match_stream(1..5){ with(List.(*_, _x, *_, _y, *_)) { [x, y] } }.to_a)
|
5
|
+
|
6
|
+
twin_primes = match_stream(Prime) {
|
7
|
+
with(List.(*_, _x, __("x + 2"), *_)) {
|
8
|
+
[x, x + 2]
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
p twin_primes.take(10)
|
13
|
+
|
14
|
+
def nats
|
15
|
+
(1..Float::INFINITY)
|
16
|
+
end
|
17
|
+
|
18
|
+
p match_stream(nats){ with(Multiset.(_m, _n, *_)) { [m, n] } }.take(10)
|
19
|
+
|
20
|
+
p match_stream(nats){ with(Set.(_m, _n, *_)) { [m, n] } }.take(10)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'egison'
|
3
|
+
require 'prime'
|
4
|
+
|
5
|
+
def twin_primes
|
6
|
+
match_stream(Prime) {
|
7
|
+
with(List.(*_, _x, __("x + 2"), *_)) {
|
8
|
+
[x, x + 2]
|
9
|
+
}
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def nats
|
14
|
+
(1..Float::INFINITY)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "sample" do
|
18
|
+
describe "stream.rb" do
|
19
|
+
it %q{match_stream(1..5){ with(List.(*_, _x, *_, _y, *_)) { [x, y] } }.to_a } do
|
20
|
+
expect(match_stream(1..5){ with(List.(*_, _x, *_, _y, *_)) { [x, y] } }.to_a).to eq \
|
21
|
+
[[1, 2], [1, 3], [2, 3], [1, 4], [2, 4], [3, 4], [1, 5], [2, 5], [3, 5], [4, 5]]
|
22
|
+
end
|
23
|
+
|
24
|
+
it %q{twin_primes.take(10)} do
|
25
|
+
expect(twin_primes.take(10)).to eq \
|
26
|
+
[[3, 5], [5, 7], [11, 13], [17, 19], [29, 31], [41, 43], [59, 61], [71, 73], [101, 103], [107, 109]]
|
27
|
+
end
|
28
|
+
|
29
|
+
# (take 10 (match-all nats (multiset integer) [<cons $m <cons $n _>> [m n]]))
|
30
|
+
it %q{match_stream(nats){ with(Multiset.(_m, _n, *_)) { [m, n] } }.take(10)} do
|
31
|
+
expect(match_stream(nats){ with(Multiset.(_m, _n, *_)) { [m, n] } }.take(10)).to eq \
|
32
|
+
[[1, 2], [1, 3], [2, 1], [1, 4], [2, 3], [3, 1], [1, 5], [2, 4], [3, 2], [4, 1]]
|
33
|
+
end
|
34
|
+
|
35
|
+
# (take 10 (match-all nats (set integer) [<cons $m <cons $n _>> [m n]]))
|
36
|
+
it %q{match_stream(nats){ with(Set.(_m, _n, *_)) { [m, n] } }.take(10)} do
|
37
|
+
expect(match_stream(nats){ with(Set.(_m, _n, *_)) { [m, n] } }.take(10)).to eq \
|
38
|
+
[[1, 1], [1, 2], [2, 1], [1, 3], [2, 2], [3, 1], [1, 4], [2, 3], [3, 2], [4, 1]]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: egison
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Satoshi Egi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-06-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -65,9 +65,11 @@ files:
|
|
65
65
|
- Makefile
|
66
66
|
- README.md
|
67
67
|
- Rakefile
|
68
|
+
- THANKS.md
|
68
69
|
- egison.gemspec
|
69
70
|
- lib/egison.rb
|
70
71
|
- lib/egison/core.rb
|
72
|
+
- lib/egison/lazyarray.rb
|
71
73
|
- lib/egison/matcher-core.rb
|
72
74
|
- lib/egison/matcher.rb
|
73
75
|
- lib/egison/version.rb
|
@@ -75,6 +77,7 @@ files:
|
|
75
77
|
- sample/join.rb
|
76
78
|
- sample/poker_hands.rb
|
77
79
|
- sample/set.rb
|
80
|
+
- sample/stream.rb
|
78
81
|
- spec/lib/egison/core_spec.rb
|
79
82
|
- spec/lib/egison/matcher_spec.rb
|
80
83
|
- spec/lib/egison_spec.rb
|
@@ -82,6 +85,7 @@ files:
|
|
82
85
|
- spec/sample/join_spec.rb
|
83
86
|
- spec/sample/poker_hands_spec.rb
|
84
87
|
- spec/sample/set_spec.rb
|
88
|
+
- spec/sample/stream_spec.rb
|
85
89
|
- spec/spec_helper.rb
|
86
90
|
homepage: https://github.com/egisatoshi/egison-ruby
|
87
91
|
licenses: []
|