egison 0.6.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4220d772a26fbea06a65175e59f77466ef5696b2
4
- data.tar.gz: 4c6a23d914dcd4a1c3c4c74f2b36258fce0c24ec
3
+ metadata.gz: 83b4172902ecda7ac29219caf4ab1fa2ecdd25df
4
+ data.tar.gz: 715dd8a2affee299c7d139f07f11e57357bb0082
5
5
  SHA512:
6
- metadata.gz: 42cb47d6867e69defec1a397afbb0f5df6bfe75ed4182ca66496a1248a2c863bd486f9e13b4a5b8834ebcf85af7b29ba06cb9e08c4e21bfd2ed8219752fa05db
7
- data.tar.gz: 5db2fa350525a714a6e514b3195a06f4adc0791cf664b92727e258956b5cf19fb24f2c4f2edf2703796693397cef633b07b5f7b8ca6811b7691e4d2c6a30d013
6
+ metadata.gz: f7750ee40919a1d41a29fcd7e9520b2d98501e1c87d3df960a5a34c770faff22e91961ba46bdaf323e6a9248b080dcdf083ee04b0938aacc3f72d6a121597591
7
+ data.tar.gz: 1475df510e8428b4d24ef9225a53e19efe4dd5747f556a7d0d9ae15a7ba61ef030e2ad3b89d4429eb6b67ff6b32ce1948c8f5c10795f21d131f281ab46b472ee
data/README.md CHANGED
@@ -5,13 +5,13 @@ We can directly express pattern-matching against lists, multisets, and sets usin
5
5
 
6
6
  ## Installation
7
7
 
8
- ```
8
+ ```shell
9
9
  $ gem install egison
10
10
  ```
11
11
 
12
12
  or
13
13
 
14
- ```
14
+ ```shell
15
15
  $ git clone https://github.com/egison/egison-ruby.git
16
16
  $ cd egison-ruby
17
17
  $ make
@@ -19,7 +19,7 @@ $ make
19
19
 
20
20
  or
21
21
 
22
- ```
22
+ ```shell
23
23
  $ gem install bundler (if you need)
24
24
  $ echo "gem 'egison', :git => 'https://github.com/egison/egison-ruby.git'" > Gemfile
25
25
  $ bundle install
@@ -29,7 +29,7 @@ $ bundle install
29
29
 
30
30
  The library provides `Egison#match_all` and `Egison#match`.
31
31
 
32
- ```
32
+ ```Ruby
33
33
  require 'egison'
34
34
 
35
35
  include Egison
@@ -63,7 +63,7 @@ If a pattern matches, it calls the block passed to the matched match-clause and
63
63
 
64
64
  ## Patterns
65
65
 
66
- ### Element patterns and subcollection patterns
66
+ ### Element Patterns and Subcollection Patterns
67
67
 
68
68
  An <i>element pattern</i> matches the element of the target array.
69
69
 
@@ -73,7 +73,7 @@ A subcollection pattern has `*` ahead.
73
73
  A literal that contain `_` ahead is a <i>pattern-variable</i>.
74
74
  We can refer the result of pattern-matching through them.
75
75
 
76
- ```
76
+ ```Ruby
77
77
  match_all([1, 2, 3]) do
78
78
  with(List.(*_hs, _x, *_ts)) do
79
79
  [hs, x, ts]
@@ -81,7 +81,7 @@ match_all([1, 2, 3]) do
81
81
  end #=> [[[],1,[2,3]],[[1],2,[3]],[[1,2],3,[]]
82
82
  ```
83
83
 
84
- ### Three matchers: List, Multiset, Set
84
+ ### Three Matchers: List, Multiset, Set
85
85
 
86
86
  We can write pattern-matching against lists, multisets, and sets.
87
87
  When we regard an array as a multiset, the order of elements is ignored.
@@ -92,7 +92,7 @@ It matches with any object.
92
92
  Note that `__` and `___` are also interpreted as a wildcard.
93
93
  This is because `_` and `__` are system variables and sometimes have its own meaning.
94
94
 
95
- ```
95
+ ```Ruby
96
96
  match_all([1, 2, 3]) do
97
97
  with(List.(_a, _b, *_)) do
98
98
  [a, b]
@@ -114,7 +114,7 @@ end #=> [[1, 1],[1, 2],[1, 3],[2, 1],[2, 2],[2, 3],[3, 1],[3, 2],[3, 3]]
114
114
 
115
115
  Note that `_[]` is provided as syntactic sugar for `List.()`.
116
116
 
117
- ```
117
+ ```Ruby
118
118
  match_all([1, 2, 3]) do
119
119
  with(_[_a, _b, *_]) do
120
120
  [a, b]
@@ -122,7 +122,7 @@ match_all([1, 2, 3]) do
122
122
  end #=> [[1, 2]]
123
123
  ```
124
124
 
125
- ### Non-linear patterns
125
+ ### Non-Linear Patterns
126
126
 
127
127
  Non-linear pattern is the most important feature of our pattern-matching system.
128
128
  Our pattern-matching system allows users multiple occurrences of same variables in a pattern.
@@ -130,7 +130,7 @@ A Pattern whose form is `__("...")` is a value pattern.
130
130
  In the place of `...`, we can write any ruby expression we like.
131
131
  It matches the target when the target is equal with the value that `...` evaluated to.
132
132
 
133
- ```
133
+ ```Ruby
134
134
  match_all([5, 3, 4, 1, 2]) do
135
135
  with(Multiset.(_a, __("a + 1"), __("a + 2"), *_)) do
136
136
  a
@@ -140,7 +140,7 @@ end #=> [1,2,3]
140
140
 
141
141
  When, the expression in the place of `...` is a single variable, we can omit `("` and `")` as follow.
142
142
 
143
- ```
143
+ ```Ruby
144
144
  match_all([1, 2, 3, 2, 5]) do
145
145
  with(Multiset.(_a, __a, *_)) do
146
146
  a
@@ -152,7 +152,7 @@ end #=> [2,2]
152
152
 
153
153
  We can do pattern-matching against streams with the `match_stream` expression.
154
154
 
155
- ```
155
+ ```Ruby
156
156
  def nats
157
157
  (1..Float::INFINITY)
158
158
  end
@@ -170,7 +170,7 @@ match_stream(nats){ with(Set.(_m, _n, *_)) { [m, n] } }.take(10)
170
170
 
171
171
  We can enumerates all combinations of the elements of a collection with pattern-matching.
172
172
 
173
- ```
173
+ ```Ruby
174
174
  require 'egison'
175
175
 
176
176
  include Egison
@@ -189,7 +189,7 @@ We can write patterns for all poker-hands in one single pattern.
189
189
  It is as follow.
190
190
  Isn't it exciting?
191
191
 
192
- ```
192
+ ```Ruby
193
193
  require 'egison'
194
194
 
195
195
  include Egison
@@ -232,20 +232,20 @@ p(poker_hands([["diamond", 4], ["club", 2], ["club", 5], ["heart", 1], ["diamond
232
232
  p(poker_hands([["diamond", 4], ["club", 10], ["club", 5], ["heart", 1], ["diamond", 3]])) #=> "Nothing"
233
233
  ```
234
234
 
235
- ### Twin Primes
235
+ ### Twin Primes and Prime Triplets
236
236
 
237
237
  The following code enumerates all twin primes with pattern-matching!
238
238
  I believe it is also a really exciting demonstration.
239
239
 
240
- ```
240
+ ```Ruby
241
241
  require 'egison'
242
242
  require 'prime'
243
243
 
244
244
  include Egison
245
245
 
246
246
  twin_primes = match_stream(Prime) {
247
- with(List.(*_, _x, __("x + 2"), *_)) {
248
- [x, x + 2]
247
+ with(List.(*_, _p, __("p + 2"), *_)) {
248
+ [p, p + 2]
249
249
  }
250
250
  }
251
251
 
@@ -253,22 +253,35 @@ p twin_primes.take(10)
253
253
  #=>[[3, 5], [5, 7], [11, 13], [17, 19], [29, 31], [41, 43], [59, 61], [71, 73], [101, 103], [107, 109]]
254
254
  ```
255
255
 
256
+ We can also enumerate prime triplets using **and-patterns** and **or-patterns** effectively.
257
+
258
+ ```Ruby
259
+ prime_triplets = match_stream(Prime) {
260
+ with(List.(*_, _p, And(Or(__("p + 2"), __("p + 4")), _m), __("p + 6"), *_)) {
261
+ [p, m, p + 6]
262
+ }
263
+ }
264
+
265
+ p prime_triplets.take(10)
266
+ #=>[[5, 7, 11], [7, 11, 13], [11, 13, 17], [13, 17, 19], [17, 19, 23], [37, 41, 43], [41, 43, 47], [67, 71, 73], [97, 101, 103], [101, 103, 107]]
267
+ ```
268
+
256
269
  ### Algebraic Data Types
257
270
 
258
271
  We can also patten match against algebraic data types as ordinary functional programming languages.
259
272
  Here is a simple example.
260
273
  Note that, the object in the pattern matches if the target object is equal with it.
261
274
 
262
- ```
275
+ ```Ruby
263
276
  class User < Struct.new(:name, :gender, :married, :doctor, :professor)
264
277
  def greet
265
278
  match(self) do
266
- with(_[_name, _, _, _, true]) { "Hello, Prof. #{name}!" }
267
- with(_[_name, _, _, true, _]) { "Hello, Dr. #{name}!" }
268
- with(_[_name, :male, _, _, _]) { "Hello, Mr. #{name}!" }
269
- with(_[_name, :female, true, _, _]) { "Hello, Mrs. #{name}!" }
270
- with(_[_name, :female, _, _, _]) { "Hello, Ms. #{name}!" }
271
- with(_[_name, _, _, _, _]) { "Hello, #{name}!" }
279
+ with(User.(_name, _, _, _, true)) { "Hello, Prof. #{name}!" }
280
+ with(User.(_name, _, _, true, _)) { "Hello, Dr. #{name}!" }
281
+ with(User.(_name, :female, true, _, _)) { "Hello, Mrs. #{name}!" }
282
+ with(User.(_name, :female, _, _, _)) { "Hello, Ms. #{name}!" }
283
+ with(User.(_name, :male, _, _, _)) { "Hello, Mr. #{name}!" }
284
+ with(User.(_name, _, _, _, _)) { "Hello, #{name}!" }
272
285
  end
273
286
  end
274
287
  end
@@ -302,12 +315,14 @@ There is a new programming world!
302
315
 
303
316
  ## Contact
304
317
 
305
- If you get interested in this Gem, please contact [Satoshi Egi](http://www.egison.org/~egi/) or tweet to [@Egison_Lang](https://twitter.com/Egison_Lang).
318
+ If you get interested in this Gem, please contact <a target="_blank" href="http://www.egison.org/~egi/">Satoshi Egi</a> or tweet to <a target="_blank" href="https://twitter.com/Egison_Lang">@Egison_Lang</a>.
319
+
320
+ We will talk about this gem in <a target="_blank" href="http://rubykaigi.org/2014">RubyKaigi 2014</a>!
306
321
 
307
322
  ## LICENSE
308
323
 
309
324
  The license of this library code is BSD.
310
- 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.
325
+ I learned how to extend Ruby and how to write a gem from the code of <a target="_blank" href="https://github.com/k-tsj/pattern-match">the pattern-match gem</a> by Kazuki Tsujimoto.
311
326
  I designed syntax of pattern-matching to go with that gem.
312
327
  This library contains the copy from that gem.
313
328
  The full license text is [here](https://github.com/egisatoshi/egison-ruby/blob/master/LICENSE).
@@ -141,10 +141,9 @@ module PatternMatch
141
141
  def match(tgt, bindings)
142
142
  tgt = tgt.to_a
143
143
  if subpatterns.empty?
144
- if tgt.empty?
145
- return [[[], []]]
146
- else
147
- return []
144
+ unnileds = @matcher.unnil(tgt)
145
+ unnileds.map do
146
+ [[], []]
148
147
  end
149
148
  else
150
149
  subpatterns = @subpatterns.clone
@@ -219,6 +218,32 @@ module PatternMatch
219
218
  end
220
219
  end
221
220
 
221
+ class OrPattern < PatternElement
222
+ attr_reader :pats
223
+
224
+ def initialize(*subpatterns)
225
+ super()
226
+ @pats = subpatterns
227
+ end
228
+
229
+ def match(tgt, bindings)
230
+ @pats.map { |pat| [[[pat, tgt]], []] }
231
+ end
232
+ end
233
+
234
+ class AndPattern < PatternElement
235
+ attr_reader :pats
236
+
237
+ def initialize(*subpatterns)
238
+ super()
239
+ @pats = subpatterns
240
+ end
241
+
242
+ def match(tgt, bindings)
243
+ [[@pats.map { |pat| [pat, tgt] }, []]]
244
+ end
245
+ end
246
+
222
247
  class Wildcard < PatternElement
223
248
  def initialize()
224
249
  super()
@@ -375,6 +400,14 @@ module PatternMatch
375
400
  end
376
401
  end
377
402
 
403
+ def Or(*subpatterns)
404
+ OrPattern.new(*subpatterns)
405
+ end
406
+
407
+ def And(*subpatterns)
408
+ AndPattern.new(*subpatterns)
409
+ end
410
+
378
411
  class BindingModule < ::Module
379
412
  end
380
413
 
@@ -4,6 +4,14 @@ require 'egison/lazyarray'
4
4
  class Class
5
5
  include PatternMatch::Matchable
6
6
 
7
+ def unnil(val)
8
+ if val.empty?
9
+ [[]]
10
+ else
11
+ []
12
+ end
13
+ end
14
+
7
15
  def uncons(val)
8
16
  raise NotImplementedError, "need to define `#{__method__}'"
9
17
  end
@@ -23,6 +31,32 @@ end
23
31
  module Egison
24
32
  extend self
25
33
 
34
+ class << Struct
35
+ def unnil(val)
36
+ [[]]
37
+ end
38
+
39
+ def uncons(val)
40
+ val2 = val.clone
41
+ x = val2.shift
42
+ [[x, val2]]
43
+ end
44
+
45
+ def unjoin(val)
46
+ val2 = val.clone
47
+ xs = []
48
+ ys = val2.clone
49
+ rets = [[xs, ys]]
50
+ until val2.empty? do
51
+ x = val2.shift
52
+ ys = val2.clone
53
+ xs += [x]
54
+ rets += [[xs, ys]]
55
+ end
56
+ rets
57
+ end
58
+ end
59
+
26
60
  class List
27
61
  end
28
62
 
@@ -1,3 +1,3 @@
1
1
  module Egison
2
- VERSION = "0.6.0"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -5,12 +5,12 @@ include Egison
5
5
  class User < Struct.new(:name, :gender, :married, :doctor, :professor)
6
6
  def greet
7
7
  match(self) do
8
- with(_[_name, _, _, _, true]) { "Hello, Prof. #{name}!" }
9
- with(_[_name, _, _, true, _]) { "Hello, Dr. #{name}!" }
10
- with(_[_name, :male, _, _, _]) { "Hello, Mr. #{name}!" }
11
- with(_[_name, :female, true, _, _]) { "Hello, Mrs. #{name}!" }
12
- with(_[_name, :female, _, _, _]) { "Hello, Ms. #{name}!" }
13
- with(_[_name, _, _, _, _]) { "Hello, #{name}!" }
8
+ with(User.(_name, _, _, _, true)) { "Hello, Prof. #{name}!" }
9
+ with(User.(_name, _, _, true)) { "Hello, Dr. #{name}!" }
10
+ with(User.(_name, :female, true)) { "Hello, Mrs. #{name}!" }
11
+ with(User.(_name, :female)) { "Hello, Ms. #{name}!" }
12
+ with(User.(_name, :male)) { "Hello, Mr. #{name}!" }
13
+ with(User.(_name)) { "Hello, #{name}!" }
14
14
  end
15
15
  end
16
16
  end
@@ -4,9 +4,17 @@ require 'prime'
4
4
  include Egison
5
5
 
6
6
  twin_primes = match_stream(Prime) {
7
- with(List.(*_, _x, __("x + 2"), *_)) {
8
- [x, x + 2]
7
+ with(List.(*_, _p, __("p + 2"), *_)) {
8
+ [p, p + 2]
9
9
  }
10
10
  }
11
11
 
12
12
  p twin_primes.take(10)
13
+
14
+ prime_triplets = match_stream(Prime) {
15
+ with(List.(*_, _p, And(Or(__("p + 2"), __("p + 4")), _m), __("p + 6"), *_)) {
16
+ [p, m, p + 6]
17
+ }
18
+ }
19
+
20
+ p prime_triplets.take(10)
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.6.0
4
+ version: 1.0.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-07-23 00:00:00.000000000 Z
11
+ date: 2014-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake