egison 0.0.1

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
+ SHA1:
3
+ metadata.gz: e5afc8d46f5b374e4e9aa32fb7b8328b9c687fd3
4
+ data.tar.gz: 37e963f48ccea8f645d18b16b29cb2a96005c436
5
+ SHA512:
6
+ metadata.gz: a999b3b1b4687d3fbc6b7ec65b5883d2992ba96478a8206ee6d7bf240475bb4113730ac2062e217c9877077f6ab2294268f98e7bcf8ab40182580d3ac459561f
7
+ data.tar.gz: 8cd1ee8f05b986418f223980e5c31491562caf7ceb4c020dd211c7d3f2ccfa4924ac6021da90ea6f029476c9dec57d1d89c7477432cfb18e52bb9c8ec88158e3
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ .bundle
2
+ Gemfile.lock
3
+ coverage
4
+ pkg/*
5
+ vendor/*
6
+ *.gem
7
+ pattern-match
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,46 @@
1
+ Copyright (C) 2012-2014 Kazuki Tsujimoto, All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
23
+
24
+ Copyright (C) 2014 Satoshi Egi, All rights reserved.
25
+
26
+ Redistribution and use in source and binary forms, with or without
27
+ modification, are permitted provided that the following conditions
28
+ are met:
29
+ 1. Redistributions of source code must retain the above copyright
30
+ notice, this list of conditions and the following disclaimer.
31
+ 2. Redistributions in binary form must reproduce the above copyright
32
+ notice, this list of conditions and the following disclaimer in the
33
+ documentation and/or other materials provided with the distribution.
34
+
35
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
36
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
39
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45
+ SUCH DAMAGE.
46
+
data/Makefile ADDED
@@ -0,0 +1,3 @@
1
+ all:
2
+ gem build egison.gemspec
3
+ gem install egison-*.gem
data/README.md ADDED
@@ -0,0 +1,206 @@
1
+ # The Gem for Egison Pattern Matching
2
+
3
+ This Gem provides a way to access Egison pattern-matching from Ruby.
4
+ Egison is the world's first programming language that can represent non-linear pattern-match against unfree data types.
5
+ We can directly express pattern-matching against lists, multisets, and sets using this gem.
6
+
7
+ ## Installation
8
+
9
+ ```
10
+ $ gem install egison
11
+ ```
12
+
13
+ or
14
+
15
+ ```
16
+ $ git clone git://github.com/egison/egison-ruby.git
17
+ $ cd egison-ruby
18
+ $ gem build egison.gemspec
19
+ $ gem install egison-*.gem
20
+ ```
21
+
22
+ or
23
+
24
+ ```
25
+ $ gem install bundler (if you need)
26
+ $ echo "gem 'egison', :git => 'git://github.com/egison/egison-ruby.git'" > Gemfile
27
+ $ bundle install --path vendor/bundle
28
+ ```
29
+
30
+ ## Basic Usage
31
+
32
+ egison library provides `Kernel#match` and `Kernel#match_all`.
33
+
34
+ ```
35
+ require 'egison'
36
+
37
+ match_all(object) do
38
+ with(pattern) do
39
+ ...
40
+ end
41
+ end
42
+
43
+ match(object) do
44
+ with(pattern) do
45
+ ...
46
+ end
47
+ with(pattern) do
48
+ ...
49
+ end
50
+ ...
51
+ end
52
+ ```
53
+
54
+ If a pattern matches, a block passed to `with` is called and returns its result.
55
+
56
+ In our pattern-matching system, there are cases that pattern-matching has multiple results.
57
+ `match_all` calls the block passed to `with` for each pattern-matching result and returns all results as an array.
58
+ `match_all` takes one single match-clause.
59
+
60
+ On the other hand, `match` takes multiple match-clauses.
61
+ It pattern-matches from the first match-clause.
62
+ If a pattern matches, it calls the block passed to the matched match-clause and returns a result for the first pattern-matching result.
63
+
64
+ ## Patterns
65
+
66
+ ### Element patterns and subcollection patterns
67
+
68
+ An <i>element pattern</i> matches the element of the target array.
69
+
70
+ A <i>subcollection pattern</i> matches the subcollection of the target array.
71
+ A subcollection pattern has `*` ahead.
72
+
73
+ A literal that contain `_` ahead is a <i>pattern-variable</i>.
74
+ We can refer the result of pattern-matching through them.
75
+
76
+ ```
77
+ match_all([1, 2, 3]) do
78
+ with(List.(*_hs, _x, *_ts)) do
79
+ [hs, x, ts]
80
+ end
81
+ end #=> [[[],1,[2,3]],[[1],2,[3]],[[1,2],3,[]]
82
+ ```
83
+
84
+ ### Three matchers: List, Multiset, Set
85
+
86
+ We can write pattern-matching against lists, multisets, and sets.
87
+ When we regard an array as a multiset, the order of elements is ignored.
88
+ When we regard an array as a set, the duplicates and order of elements are ignored.
89
+
90
+ ```
91
+ match_all([1, 2, 3]) do
92
+ with(List.(_a, _b, *_)) do
93
+ [a, b]
94
+ end
95
+ end #=> [[1, 2]]
96
+
97
+ match_all([1, 2, 3]) do
98
+ with(Multiset.(_a, _b, *_)) do
99
+ [a, b]
100
+ end
101
+ end #=> [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
102
+
103
+ match_all([1, 2, 3]) do
104
+ with(Set.(_a, _b, *_)) do
105
+ [a, b]
106
+ end
107
+ end #=> [[1, 1],[1, 2],[1, 3],[2, 1],[2, 2],[2, 3],[3, 1],[3, 2],[3, 3]]
108
+ ```
109
+
110
+ ### Non-linear patterns
111
+
112
+ Non-linear pattern is the most important feature of our pattern-matching system.
113
+ Our pattern-matching system allows users multiple occurrences of same variables in a pattern.
114
+ A Pattern whose form is `__("...")` is a value pattern.
115
+ In the place of `...`, we can write any ruby expression we like.
116
+ It matches the target when the target is equal with the value that `...` evaluated to.
117
+
118
+ ```
119
+ match_all([5, 3, 4, 1, 2]) do
120
+ with(Multiset.(_a, __("a + 1"), __("a + 2"), *_)) do
121
+ a
122
+ end
123
+ end #=> [1,2,3]
124
+ ```
125
+
126
+ When, the expression in the place of `...` is a single variable, we can omit `("` and `")` as follow.
127
+
128
+ ```
129
+ match_all([1, 2, 3, 2, 5]) do
130
+ with(Multiset.(_a, __a, *_)) do
131
+ a
132
+ end
133
+ end #=> [2,2]
134
+ ```
135
+
136
+ ## Demonstration - Poker Hands
137
+
138
+ We can write patterns for all poker-hands in one single pattern.
139
+ It is as follow.
140
+ Isn't it exciting?
141
+
142
+ ```
143
+ require 'egison'
144
+
145
+ def poker_hands cs
146
+ match(cs) do
147
+ with(Multiset.(_[_s, _n], _[__s, __("n+1")], _[__s, __("n+2")], _[__s, __("n+3")], _[__s, __("n+4")])) do
148
+ "Straight flush"
149
+ end
150
+ with(Multiset.(_[_, _n], _[_, __n], _[_, __n], _[_, __n], _)) do
151
+ "Four of kind"
152
+ end
153
+ with(Multiset.(_[_, _m], _[_, __m], _[_, __m], _[_, _n], _[_, __n])) do
154
+ "Full house"
155
+ end
156
+ with(Multiset.(_[_s, _], _[__s, _], _[__s, _], _[__s, _], _[__s, _])) do
157
+ "Flush"
158
+ end
159
+ with(Multiset.(_[_, _n], _[_, __("n+1")], _[_, __("n+2")], _[_, __("n+3")], _[_, __("n+4")])) do
160
+ "Straight"
161
+ end
162
+ with(Multiset.(_[_, _n], _[_, __n], _[_, __n], _, _)) do
163
+ "Three of kind"
164
+ end
165
+ with(Multiset.(_[_, _m], _[_, __m], _[_, _n], _[_, __n], _)) do
166
+ "Two pairs"
167
+ end
168
+ with(Multiset.(_[_, _n], _[_, __n], _, _, _)) do
169
+ "One pair"
170
+ end
171
+ with(Multiset.(_, _, _, _, _)) do
172
+ "Nothing"
173
+ end
174
+ end
175
+ end
176
+
177
+ p(poker_hands([["diamond", 1], ["diamond", 3], ["diamond", 5], ["diamond", 4], ["diamond", 2]])) #=> "Straight flush"
178
+ p(poker_hands([["diamond", 1], ["club", 2], ["club", 1], ["heart", 1], ["diamond", 2]])) #=> "Full house"
179
+ p(poker_hands([["diamond", 4], ["club", 2], ["club", 5], ["heart", 1], ["diamond", 3]])) #=> "Straight"
180
+ p(poker_hands([["diamond", 4], ["club", 10], ["club", 5], ["heart", 1], ["diamond", 3]])) #=> "Nothing"
181
+ ```
182
+
183
+ ## About Egison
184
+
185
+ If you get to love the above pattern-matching, please try [the Egison programming language](http://www.egison.org), too.
186
+ Egison is the pattern-matching oriented pure functional programming language.
187
+ Actually, the original pattern-matching system of Egison is more powerful.
188
+ For example, we can do following things in the original Egison.
189
+
190
+ - We can pattern-match against infinite lists
191
+ - We can define new pattern-constructors.
192
+ - We can modularize useful patterns.
193
+
194
+ There is a new programming world!
195
+
196
+ ## Contact
197
+
198
+ If you get interested in this Gem, please mail to [Satoshi Egi](http://www.egison.org/~egi/) or tweet to [@Egison_Lang](https://twitter.com/Egison_Lang).
199
+
200
+ ## LICENSE
201
+
202
+ The license of this library code is BSD.
203
+ I learned how to extend Ruby and how to write a gem from the code of [the pattern-match gem](https://github.com/k-tsj/pattern-match) by Kazuki Tsujimoto.
204
+ I designed syntax of pattern-matching to go with that gem.
205
+ This library contains the copy from that gem.
206
+ The full license text is [here](https://github.com/egisatoshi/egison-ruby/blob/master/LICENSE).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', __FILE__)
2
+ require 'bundler/setup'
3
+ require "bundler/gem_tasks"
4
+
5
+ require "rake/testtask"
6
+ task :default => :test
7
+ Rake::TestTask.new do |t|
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/test_*.rb"]
10
+ end
data/egison.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ $:.push File.expand_path('../lib', __FILE__)
2
+ require 'egison/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'egison'
6
+ s.version = Egison::VERSION
7
+ s.authors = ['Satoshi Egi']
8
+ s.email = ['egi@egison.org']
9
+ s.homepage = 'https://github.com/egisatoshi/egison-ruby'
10
+ s.summary = %q{The Egison pattern matching library}
11
+ s.description = %w{
12
+ The library to access Egison pattern-matching from Ruby.
13
+ }.join(' ')
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f) }
18
+ s.require_paths = ['lib']
19
+ s.add_development_dependency 'rake'
20
+ s.rdoc_options = ['--main', 'README.rdoc']
21
+ end
data/lib/egison.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'egison/version'
2
+ require 'egison/core'
3
+ require 'egison/matcher'
@@ -0,0 +1,355 @@
1
+ require 'egison/version'
2
+ require 'continuation'
3
+
4
+ module PatternMatch
5
+ module Matchable
6
+ def call(*subpatterns)
7
+ pattern_matcher(*subpatterns)
8
+ end
9
+ end
10
+
11
+ class ::Object
12
+ private
13
+
14
+ def pattern_matcher(*subpatterns)
15
+ PatternWithMatcher.new(self, *subpatterns)
16
+ end
17
+ end
18
+
19
+ class MatchingStateStack
20
+ attr_accessor :states
21
+ attr_accessor :results
22
+
23
+ def initialize(pat, tgt)
24
+ @states = [MatchingState.new(pat, tgt)]
25
+ @results = []
26
+ end
27
+
28
+ def match
29
+ while !@states.empty? do
30
+ process
31
+ end
32
+ @results
33
+ end
34
+
35
+ def process
36
+ state = @states.shift
37
+ rets = state.process
38
+ new_states = []
39
+ rets.each { |ret|
40
+ if ret.atoms.empty? then
41
+ @results = @results + [ret.bindings]
42
+ else
43
+ new_states = new_states + [ret]
44
+ end
45
+ }
46
+ @states = new_states + @states
47
+ end
48
+ end
49
+
50
+ class MatchingState
51
+ attr_accessor :atoms, :bindings
52
+
53
+ def initialize(pat, tgt)
54
+ @atoms = [[pat, tgt]]
55
+ @bindings = []
56
+ end
57
+
58
+ def process
59
+ atom = @atoms.shift
60
+ rets = atom.first.match(atom.last, @bindings)
61
+ rets.map { |new_atoms, new_bindings|
62
+ new_state = self.clone
63
+ new_state.atoms = new_atoms + new_state.atoms
64
+ new_state.bindings = new_state.bindings + new_bindings
65
+ new_state
66
+ }
67
+ end
68
+ end
69
+
70
+ class Pattern
71
+ attr_accessor :quantified
72
+
73
+ def initialize
74
+ end
75
+
76
+ def match(tgt, bindings)
77
+ end
78
+
79
+ def to_a
80
+ [PatternCollection.new(self)]
81
+ end
82
+ end
83
+
84
+ class PatternElement < Pattern
85
+ def initialize
86
+ super()
87
+ @quantified = false
88
+ end
89
+ end
90
+
91
+ class PatternWithMatcher < PatternElement
92
+ attr_reader :matcher, :subpatterns
93
+
94
+ def initialize(matcher, *subpatterns)
95
+ super()
96
+ @matcher = matcher
97
+ @subpatterns = subpatterns
98
+ end
99
+
100
+ def match(tgt, bindings)
101
+ if subpatterns.empty? then
102
+ if tgt.empty? then
103
+ return [[[], []]]
104
+ else
105
+ return []
106
+ end
107
+ else
108
+ subpatterns = @subpatterns.clone
109
+ px = subpatterns.shift
110
+ if px.quantified then
111
+ if subpatterns.empty? then
112
+ [[[[px.pattern, tgt]], []]]
113
+ else
114
+ unjoineds = @matcher.unjoin(tgt)
115
+ unjoineds.map { |xs, ys| [[[px.pattern, xs], [PatternWithMatcher.new(@matcher, *subpatterns), ys]], []] }
116
+ end
117
+ else
118
+ if tgt.empty? then
119
+ []
120
+ else
121
+ unconseds = @matcher.uncons(tgt)
122
+ unconseds.map { |x, xs| [[[px, x], [PatternWithMatcher.new(@matcher, *subpatterns), xs]], []] }
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ class Wildcard < PatternElement
130
+ def initialize()
131
+ super()
132
+ end
133
+
134
+ def match(tgt, bindings)
135
+ [[[], []]]
136
+ end
137
+ end
138
+
139
+ class PatternVariable < PatternElement
140
+ attr_reader :name
141
+
142
+ def initialize(name)
143
+ super()
144
+ @name = name
145
+ end
146
+
147
+ def match(tgt, bindings)
148
+ [[[], [[name, tgt]]]]
149
+ end
150
+ end
151
+
152
+ class ValuePattern < PatternElement
153
+ def initialize(ctx, expr)
154
+ super()
155
+ @ctx = ctx
156
+ @expr = expr
157
+ end
158
+
159
+ def match(tgt, bindings)
160
+ val = with_bindings(@ctx, bindings, {:expr => @expr}) { eval expr }
161
+ if val.__send__(:===, tgt) then
162
+ [[[], []]]
163
+ else
164
+ []
165
+ end
166
+ end
167
+
168
+ class BindingModule < ::Module
169
+ end
170
+
171
+ def with_bindings(obj, bindings, ext_bindings, &block)
172
+ binding_module(obj).module_eval do
173
+ begin
174
+ bindings.each do |name, val|
175
+ define_method(name) { val }
176
+ private name
177
+ end
178
+ ext_bindings.each do |name, val|
179
+ define_method(name) { val }
180
+ private name
181
+ end
182
+ obj.instance_eval(&block)
183
+ ensure
184
+ bindings.each do |name, _|
185
+ remove_method(name)
186
+ end
187
+ ext_bindings.each do |name, _|
188
+ remove_method(name)
189
+ end
190
+ end
191
+ end
192
+ end
193
+
194
+ def binding_module(obj)
195
+ m = obj.singleton_class.ancestors.find {|i| i.kind_of?(BindingModule) }
196
+ unless m
197
+ m = BindingModule.new
198
+ obj.singleton_class.class_eval do
199
+ if respond_to?(:prepend, true)
200
+ prepend m
201
+ else
202
+ include m
203
+ end
204
+ end
205
+ end
206
+ m
207
+ end
208
+ end
209
+
210
+ class PatternCollection < Pattern
211
+ attr_accessor :pattern
212
+
213
+ def initialize(pat)
214
+ super()
215
+ @quantified = true
216
+ @pattern = pat
217
+ end
218
+ end
219
+
220
+ class Env < BasicObject
221
+ def initialize(ctx, tgt)
222
+ @ctx = ctx
223
+ @tgt = tgt
224
+ end
225
+
226
+ private
227
+
228
+ def with(pat, &block)
229
+ ctx = @ctx
230
+ tgt = @tgt
231
+ mstack = MatchingStateStack.new(pat,tgt)
232
+ mstack.match
233
+ mstack.results.map { |bindings|
234
+ ret = with_bindings(ctx, bindings, &block)
235
+ }
236
+ rescue PatternNotMatch
237
+ end
238
+
239
+ def method_missing(name, *args)
240
+ ::Kernel.raise ::ArgumentError, "wrong number of arguments (#{args.length} for 0)" unless args.empty?
241
+ if /^__/.match(name.to_s)
242
+ ValuePattern.new(@ctx, name.to_s.gsub(/^__/, "").gsub("_plus_", "+").gsub("_minus_", "-"))
243
+ elsif /^_/.match(name.to_s)
244
+ PatternVariable.new(name.to_s.gsub(/^_/, "").to_sym)
245
+ else
246
+ undefined
247
+ end
248
+ end
249
+
250
+ def _(*vals)
251
+ case vals.length
252
+ when 0
253
+ uscore = Wildcard.new()
254
+ class << uscore
255
+ def [](*args)
256
+ List.call(*args)
257
+ end
258
+ end
259
+ uscore
260
+ when 1
261
+ ValuePattern.new(@ctx, vals[0])
262
+ else
263
+ undefined
264
+ end
265
+ end
266
+
267
+ def __(val)
268
+ ValuePattern.new(@ctx, val)
269
+ end
270
+
271
+ class BindingModule < ::Module
272
+ end
273
+
274
+ def with_bindings(obj, bindings, &block)
275
+ binding_module(obj).module_eval do
276
+ begin
277
+ bindings.each do |name, val|
278
+ define_method(name) { val }
279
+ private name
280
+ end
281
+ obj.instance_eval(&block)
282
+ ensure
283
+ bindings.each do |name, _|
284
+ remove_method(name)
285
+ end
286
+ end
287
+ end
288
+ end
289
+
290
+ def binding_module(obj)
291
+ m = obj.singleton_class.ancestors.find {|i| i.kind_of?(BindingModule) }
292
+ unless m
293
+ m = BindingModule.new
294
+ obj.singleton_class.class_eval do
295
+ if respond_to?(:prepend, true)
296
+ prepend m
297
+ else
298
+ include m
299
+ end
300
+ end
301
+ end
302
+ m
303
+ end
304
+ end
305
+
306
+ class Env2 < Env
307
+ def with(pat, &block)
308
+ ctx = @ctx
309
+ tgt = @tgt
310
+ mstack = MatchingStateStack.new(pat,tgt)
311
+ mstack.match
312
+ if mstack.results.empty? then
313
+ nil
314
+ else
315
+ ret = with_bindings(ctx, mstack.results.first, &block)
316
+ ::Kernel.throw(:exit_match, ret)
317
+ end
318
+ rescue PatternNotMatch
319
+ end
320
+ end
321
+
322
+ class PatternNotMatch < Exception; end
323
+ class PatternMatchError < StandardError; end
324
+ class NoMatchingPatternError < PatternMatchError; end
325
+ class MalformedPatternError < PatternMatchError; end
326
+
327
+ # Make Pattern and its subclasses/Env private.
328
+ if respond_to?(:private_constant)
329
+ constants.each do |c|
330
+ klass = const_get(c)
331
+ next unless klass.kind_of?(Class)
332
+ if klass <= Pattern
333
+ private_constant c
334
+ end
335
+ end
336
+ private_constant :Env, :Env2
337
+ end
338
+ end
339
+
340
+ module Kernel
341
+ private
342
+
343
+ def match_all(tgt, &block)
344
+ env = PatternMatch.const_get(:Env).new(self, tgt)
345
+ env.instance_eval(&block)
346
+ end
347
+
348
+ def match(tgt, &block)
349
+ env = PatternMatch.const_get(:Env2).new(self, tgt)
350
+ catch(:exit_match) do
351
+ env.instance_eval(&block)
352
+ end
353
+ end
354
+
355
+ end
@@ -0,0 +1,104 @@
1
+ require 'egison/core'
2
+
3
+ class Class
4
+ include PatternMatch::Matchable
5
+
6
+ def uncons(val)
7
+ raise NotImplementedError, "need to define `#{__method__}'"
8
+ end
9
+
10
+ private
11
+
12
+ def accept_array_only(val)
13
+ raise PatternMatch::PatternNotMatch unless val.kind_of?(Array)
14
+ end
15
+ end
16
+
17
+ class List
18
+ end
19
+
20
+ class << List
21
+ def uncons(val)
22
+ accept_array_only(val)
23
+ val2 = val.clone
24
+ x = val2.shift
25
+ [[x, val2]]
26
+ end
27
+
28
+ def unjoin(val)
29
+ accept_array_only(val)
30
+ val2 = val.clone
31
+ xs = []
32
+ ys = val2.clone
33
+ rets = [[xs, ys]]
34
+ while !val2.empty? do
35
+ x = val2.shift
36
+ ys = val2.clone
37
+ xs = xs + [x]
38
+ rets = rets + [[xs, ys]]
39
+ end
40
+ rets
41
+ end
42
+ end
43
+
44
+ class Multiset
45
+ end
46
+
47
+ class << Multiset
48
+ def uncons(val)
49
+ accept_array_only(val)
50
+ rets = val.map {|x|
51
+ val2 = val.clone
52
+ val2.delete_at(val2.find_index(x))
53
+ [x, val2]
54
+ }
55
+ rets
56
+ end
57
+
58
+ def unjoin(val)
59
+ accept_array_only(val)
60
+ val2 = val.clone
61
+ xs = []
62
+ ys = val2.clone
63
+ rets = [[xs, ys]]
64
+ if !val2.empty? then
65
+ x = val2.shift
66
+ ys = val2.clone
67
+ rets2 = unjoin(ys)
68
+ rets = (rets2.map {|xs2, ys2| [xs2, [x]+ys2]}) + (rets2.map {|xs2, ys2| [[x]+xs2, ys2]})
69
+ rets
70
+ else
71
+ rets
72
+ end
73
+ end
74
+ end
75
+
76
+ class Set
77
+ end
78
+
79
+ class << Set
80
+ def uncons(val)
81
+ accept_array_only(val)
82
+ rets = val.map {|x|
83
+ val2 = val.clone
84
+ [x, val2]
85
+ }
86
+ rets
87
+ end
88
+ def unjoin(val)
89
+ accept_array_only(val)
90
+ val2 = val.clone
91
+ xs = []
92
+ ys = val2.clone
93
+ rets = [[xs, ys]]
94
+ if !val2.empty? then
95
+ x = val2.shift
96
+ ys2 = val2.clone
97
+ rets2 = unjoin(ys2)
98
+ rets = (rets2.map {|xs2, _| [xs2, ys]}) + (rets2.map {|xs2, ys2| [[x]+xs2, ys]})
99
+ rets
100
+ else
101
+ rets
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,3 @@
1
+ module Egison
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,5 @@
1
+ require 'egison'
2
+
3
+ p(match_all([1,2,3,4,5]) do with(List.(*_, _x, *_, _y, *_)) { [x, y] } end)
4
+
5
+ p(match_all([1,2,3,4,5]) do with(List.(*_, _x, *_, _y, *_, _z, *_)) { [x, y, z] } end)
@@ -0,0 +1,38 @@
1
+ require 'egison'
2
+
3
+ def poker_hands cs
4
+ match(cs) do
5
+ with(Multiset.(_[_s, _n], _[__s, __("n+1")], _[__s, __("n+2")], _[__s, __("n+3")], _[__s, __("n+4")])) do
6
+ "Straight flush"
7
+ end
8
+ with(Multiset.(_[_, _n], _[_, __n], _[_, __n], _[_, __n], _)) do
9
+ "Four of kind"
10
+ end
11
+ with(Multiset.(_[_, _m], _[_, __m], _[_, __m], _[_, _n], _[_, __n])) do
12
+ "Full house"
13
+ end
14
+ with(Multiset.(_[_s, _], _[__s, _], _[__s, _], _[__s, _], _[__s, _])) do
15
+ "Flush"
16
+ end
17
+ with(Multiset.(_[_, _n], _[_, __("n+1")], _[_, __("n+2")], _[_, __("n+3")], _[_, __("n+4")])) do
18
+ "Straight"
19
+ end
20
+ with(Multiset.(_[_, _n], _[_, __n], _[_, __n], _, _)) do
21
+ "Three of kind"
22
+ end
23
+ with(Multiset.(_[_, _m], _[_, __m], _[_, _n], _[_, __n], _)) do
24
+ "Two pairs"
25
+ end
26
+ with(Multiset.(_[_, _n], _[_, __n], _, _, _)) do
27
+ "One pair"
28
+ end
29
+ with(Multiset.(_, _, _, _, _)) do
30
+ "Nothing"
31
+ end
32
+ end
33
+ end
34
+
35
+ p(poker_hands([["diamond", 1], ["diamond", 3], ["diamond", 5], ["diamond", 4], ["diamond", 2]])) #=> "Straight flush"
36
+ p(poker_hands([["diamond", 1], ["club", 2], ["club", 1], ["heart", 1], ["diamond", 2]])) #=> "Full house"
37
+ p(poker_hands([["diamond", 4], ["club", 2], ["club", 5], ["heart", 1], ["diamond", 3]])) #=> "Straight"
38
+ p(poker_hands([["diamond", 4], ["club", 10], ["club", 5], ["heart", 1], ["diamond", 3]])) #=> "Nothing"
data/sample/set.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'egison'
2
+
3
+ p(match_all([1,2,3,4,5]) do with(Set.(_x,_y, *_)) { [x, y] } end)
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: egison
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Satoshi Egi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: The library to access Egison pattern-matching from Ruby.
28
+ email:
29
+ - egi@egison.org
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".gitignore"
35
+ - Gemfile
36
+ - LICENSE
37
+ - Makefile
38
+ - README.md
39
+ - Rakefile
40
+ - egison.gemspec
41
+ - lib/egison.rb
42
+ - lib/egison/core.rb
43
+ - lib/egison/matcher.rb
44
+ - lib/egison/version.rb
45
+ - sample/combination.rb
46
+ - sample/poker_hands.rb
47
+ - sample/set.rb
48
+ homepage: https://github.com/egisatoshi/egison-ruby
49
+ licenses: []
50
+ metadata: {}
51
+ post_install_message:
52
+ rdoc_options:
53
+ - "--main"
54
+ - README.rdoc
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project:
69
+ rubygems_version: 2.2.2
70
+ signing_key:
71
+ specification_version: 4
72
+ summary: The Egison pattern matching library
73
+ test_files: []