egison 0.0.1

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
+ 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: []