hamster 0.1.23 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/History.rdoc +26 -0
  2. data/README.rdoc +1 -1
  3. data/lib/hamster.rb +1 -1
  4. data/lib/hamster/core_ext/io.rb +7 -5
  5. data/lib/hamster/hash.rb +31 -29
  6. data/lib/hamster/list.rb +203 -128
  7. data/lib/hamster/set.rb +39 -25
  8. data/lib/hamster/stack.rb +9 -5
  9. data/lib/hamster/trie.rb +5 -1
  10. data/lib/hamster/version.rb +1 -1
  11. data/spec/hamster/hash/all_spec.rb +29 -25
  12. data/spec/hamster/hash/reduce_spec.rb +1 -1
  13. data/spec/hamster/hash/uniq_spec.rb +23 -0
  14. data/spec/hamster/list/all_spec.rb +55 -55
  15. data/spec/hamster/list/any_spec.rb +4 -8
  16. data/spec/hamster/list/append_spec.rb +2 -20
  17. data/spec/hamster/list/break_spec.rb +22 -121
  18. data/spec/hamster/list/cadr_spec.rb +4 -0
  19. data/spec/hamster/list/chunk_spec.rb +6 -0
  20. data/spec/hamster/list/combinations_spec.rb +51 -0
  21. data/spec/hamster/list/count_spec.rb +4 -8
  22. data/spec/hamster/list/cycle_spec.rb +5 -24
  23. data/spec/hamster/list/drop_spec.rb +2 -14
  24. data/spec/hamster/list/drop_while_spec.rb +2 -14
  25. data/spec/hamster/list/each_spec.rb +4 -8
  26. data/spec/hamster/list/eql_spec.rb +9 -10
  27. data/spec/hamster/list/filter_spec.rb +2 -20
  28. data/spec/hamster/list/find_spec.rb +4 -8
  29. data/spec/hamster/list/grep_spec.rb +2 -20
  30. data/spec/hamster/list/include_spec.rb +4 -8
  31. data/spec/hamster/list/init_spec.rb +4 -0
  32. data/spec/hamster/list/inits_spec.rb +42 -0
  33. data/spec/hamster/list/inspect_spec.rb +4 -8
  34. data/spec/hamster/list/intersperse_spec.rb +2 -14
  35. data/spec/hamster/list/join_spec.rb +4 -8
  36. data/spec/hamster/list/last_spec.rb +4 -8
  37. data/spec/hamster/list/map_spec.rb +2 -14
  38. data/spec/hamster/list/maximum_spec.rb +4 -8
  39. data/spec/hamster/list/minimum_spec.rb +4 -8
  40. data/spec/hamster/list/none_spec.rb +4 -8
  41. data/spec/hamster/list/one_spec.rb +4 -8
  42. data/spec/hamster/list/partition_spec.rb +12 -111
  43. data/spec/hamster/list/product_spec.rb +4 -8
  44. data/spec/hamster/list/reduce_spec.rb +4 -8
  45. data/spec/hamster/list/remove_spec.rb +2 -14
  46. data/spec/hamster/list/reverse_spec.rb +4 -8
  47. data/spec/hamster/list/size_spec.rb +4 -8
  48. data/spec/hamster/list/sorting_spec.rb +2 -14
  49. data/spec/hamster/list/span_spec.rb +22 -121
  50. data/spec/hamster/list/split_at_spec.rb +2 -65
  51. data/spec/hamster/list/sum_spec.rb +4 -8
  52. data/spec/hamster/list/tails_spec.rb +42 -0
  53. data/spec/hamster/list/take_spec.rb +2 -14
  54. data/spec/hamster/list/take_while_spec.rb +2 -14
  55. data/spec/hamster/list/to_a_spec.rb +4 -8
  56. data/spec/hamster/list/to_ary_spec.rb +4 -8
  57. data/spec/hamster/list/union_spec.rb +1 -21
  58. data/spec/hamster/list/uniq_spec.rb +3 -15
  59. data/spec/hamster/list/zip_spec.rb +1 -21
  60. data/spec/hamster/set/all_spec.rb +33 -29
  61. data/spec/hamster/set/product_spec.rb +32 -0
  62. data/spec/hamster/set/sum_spec.rb +32 -0
  63. data/spec/hamster/set/uniq_spec.rb +1 -1
  64. data/spec/spec.opts +0 -1
  65. metadata +8 -2
data/History.rdoc CHANGED
@@ -1,3 +1,29 @@
1
+ === 0.2.0 / 2010-01-14
2
+
3
+ * List methods that return lists are now all lazy. Not sure what, if any, negative impact this will have but the positives have so far been well worth it.
4
+
5
+ * Ensure List#eql? (and #==) doesn't accidentally consider an empty list to be equal to an empty array!
6
+
7
+ * Ensure List responds_to? cadr and friends.
8
+
9
+ * Stream now releases the block for garbage collection once called.
10
+
11
+ * Implement List#combinations.
12
+
13
+ * Implement List#inits.
14
+
15
+ * Implement List#tails.
16
+
17
+ * Implement Hash#uniq.
18
+
19
+ * Alias #uniq as #remove_duplicates.
20
+
21
+ * Alias #all? as #forall?
22
+
23
+ * Implement Set#product.
24
+
25
+ * Implement Set#sum.
26
+
1
27
  === 0.1.23 / 2010-01-11
2
28
 
3
29
  * Implement List#product.
data/README.rdoc CHANGED
@@ -170,7 +170,7 @@ How is this even possible? It's possible because <tt>IO#to_list</tt> creates a l
170
170
 
171
171
  Hamster started out as a spike to prove a point and has since morphed into something I actually use. My primary concern has been to round out the functionality with good test coverage and clean, readable code.
172
172
 
173
- Performance is pretty good--especially with lazy lists--but there are some things which unfortunately had to be converted from recursive to iterative due to a lack of Tail-Call-Optimisation in Ruby, making them a little less readable, and a little more memory hungry, than I would otherwise have preferred.
173
+ Performance is pretty good--especially with lazy lists--but there are some things which may blow the stack due to a lack of Tail-Call-Optimisation in Ruby.
174
174
 
175
175
  Documentation is sparse but I've tried as best I can to write specs that read as documentation. I've also tried to alias methods as their <tt>Enumerable</tt> equivalents where possible to make it easier for people to migrate code.
176
176
 
data/lib/hamster.rb CHANGED
@@ -1,6 +1,6 @@
1
+ require 'hamster/core_ext'
1
2
  require 'hamster/list'
2
3
  require 'hamster/stack'
3
4
  require 'hamster/set'
4
5
  require 'hamster/hash'
5
- require 'hamster/core_ext'
6
6
  require 'hamster/version'
@@ -7,11 +7,13 @@ module Hamster
7
7
  module IO
8
8
 
9
9
  def to_list(sep = $/)
10
- line = gets(sep)
11
- if line
12
- Stream.new(line) { to_list }
13
- else
14
- EmptyList
10
+ Stream.new do
11
+ line = gets(sep)
12
+ if line
13
+ Sequence.new(line, to_list)
14
+ else
15
+ EmptyList
16
+ end
15
17
  end
16
18
  end
17
19
 
data/lib/hamster/hash.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'forwardable'
2
+
1
3
  require 'hamster/trie'
2
4
 
3
5
  module Hamster
@@ -8,6 +10,8 @@ module Hamster
8
10
 
9
11
  class Hash
10
12
 
13
+ extend Forwardable
14
+
11
15
  def initialize(trie = Trie.new)
12
16
  @trie = trie
13
17
  end
@@ -15,19 +19,19 @@ module Hamster
15
19
  def size
16
20
  @trie.size
17
21
  end
18
- alias_method :length, :size
22
+ def_delegator :self, :size, :length
19
23
 
20
24
  def empty?
21
25
  @trie.empty?
22
26
  end
23
- alias_method :null?, :empty?
27
+ def_delegator :self, :empty?, :null?
24
28
 
25
29
  def has_key?(key)
26
30
  @trie.has_key?(key)
27
31
  end
28
- alias_method :key?, :has_key?
29
- alias_method :include?, :has_key?
30
- alias_method :member?, :has_key?
32
+ def_delegator :self, :has_key?, :key?
33
+ def_delegator :self, :has_key?, :include?
34
+ def_delegator :self, :has_key?, :member?
31
35
 
32
36
  def get(key)
33
37
  entry = @trie.get(key)
@@ -35,12 +39,12 @@ module Hamster
35
39
  entry.value
36
40
  end
37
41
  end
38
- alias_method :[], :get
42
+ def_delegator :self, :get, :[]
39
43
 
40
44
  def put(key, value)
41
45
  self.class.new(@trie.put(key, value))
42
46
  end
43
- alias_method :[]=, :put
47
+ def_delegator :self, :put, :[]=
44
48
 
45
49
  def delete(key)
46
50
  trie = @trie.delete(key)
@@ -55,7 +59,7 @@ module Hamster
55
59
  return self unless block_given?
56
60
  @trie.each { |entry| yield(entry.key, entry.value) }
57
61
  end
58
- alias_method :foreach, :each
62
+ def_delegator :self, :each, :foreach
59
63
 
60
64
  def map
61
65
  return self unless block_given?
@@ -65,14 +69,14 @@ module Hamster
65
69
  self.class.new(@trie.reduce(Trie.new) { |trie, entry| trie.put(*yield(entry.key, entry.value)) })
66
70
  end
67
71
  end
68
- alias_method :collect, :map
72
+ def_delegator :self, :map, :collect
69
73
 
70
74
  def reduce(memo)
71
75
  return memo unless block_given?
72
76
  @trie.reduce(memo) { |memo, entry| yield(memo, entry.key, entry.value) }
73
77
  end
74
- alias_method :inject, :reduce
75
- alias_method :fold, :reduce
78
+ def_delegator :self, :reduce, :inject
79
+ def_delegator :self, :reduce, :fold
76
80
 
77
81
  def filter
78
82
  return self unless block_given?
@@ -83,26 +87,23 @@ module Hamster
83
87
  self.class.new(trie)
84
88
  end
85
89
  end
86
- alias_method :select, :filter
87
- alias_method :find_all, :filter
90
+ def_delegator :self, :filter, :select
91
+ def_delegator :self, :filter, :find_all
88
92
 
89
93
  def remove
90
94
  return self unless block_given?
91
95
  filter { |key, value| !yield(key, value) }
92
96
  end
93
- alias_method :reject, :remove
94
- alias_method :delete_if, :remove
97
+ def_delegator :self, :remove, :reject
98
+ def_delegator :self, :remove, :delete_if
95
99
 
96
100
  def any?
97
- if block_given?
98
- each { |key, value| return true if yield(key, value) }
99
- else
100
- return !empty?
101
- end
101
+ return !empty? unless block_given?
102
+ each { |key, value| return true if yield(key, value) }
102
103
  false
103
104
  end
104
- alias_method :exist?, :any?
105
- alias_method :exists?, :any?
105
+ def_delegator :self, :any?, :exist?
106
+ def_delegator :self, :any?, :exists?
106
107
 
107
108
  def all?
108
109
  if block_given?
@@ -110,25 +111,26 @@ module Hamster
110
111
  end
111
112
  true
112
113
  end
114
+ def_delegator :self, :all?, :forall?
113
115
 
114
116
  def none?
115
- if block_given?
116
- each { |key, value| return false if yield(key, value) }
117
- else
118
- return empty?
119
- end
117
+ return empty? unless block_given?
118
+ each { |key, value| return false if yield(key, value) }
120
119
  true
121
120
  end
122
121
 
123
122
  def eql?(other)
124
123
  other.is_a?(self.class) && @trie.eql?(other.instance_eval{@trie})
125
124
  end
126
- alias_method :==, :eql?
125
+ def_delegator :self, :eql?, :==
127
126
 
128
127
  def dup
129
128
  self
130
129
  end
131
- alias_method :clone, :dup
130
+ def_delegator :self, :dup, :clone
131
+ def_delegator :self, :dup, :uniq
132
+ def_delegator :self, :dup, :nub
133
+ def_delegator :self, :dup, :remove_duplicates
132
134
 
133
135
  end
134
136
 
data/lib/hamster/list.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'forwardable'
1
2
  require 'monitor'
2
3
 
3
4
  require 'hamster/set'
@@ -6,23 +7,25 @@ module Hamster
6
7
 
7
8
  class << self
8
9
 
10
+ extend Forwardable
11
+
9
12
  def list(*items)
10
13
  items.reverse.reduce(EmptyList) { |list, item| list.cons(item) }
11
14
  end
12
15
 
13
16
  def stream(&block)
14
17
  return EmptyList unless block_given?
15
- Stream.new(yield) { stream(&block) }
18
+ Stream.new { Sequence.new(yield, stream(&block)) }
16
19
  end
17
20
 
18
21
  def interval(from, to)
19
22
  return EmptyList if from > to
20
- Stream.new(from) { interval(from.succ, to) }
23
+ Stream.new { Sequence.new(from, interval(from.succ, to)) }
21
24
  end
22
- alias_method :range, :interval
25
+ def_delegator :self, :interval, :range
23
26
 
24
27
  def repeat(item)
25
- Stream.new(item) { repeat(item) }
28
+ Stream.new { Sequence.new(item, repeat(item)) }
26
29
  end
27
30
 
28
31
  def replicate(number, item)
@@ -30,29 +33,37 @@ module Hamster
30
33
  end
31
34
 
32
35
  def iterate(item, &block)
33
- Stream.new(item) { iterate(yield(item), &block) }
36
+ Stream.new { Sequence.new(item, iterate(yield(item), &block)) }
34
37
  end
35
38
 
36
39
  end
37
40
 
38
41
  module List
39
42
 
43
+ extend Forwardable
44
+
40
45
  Undefined = Object.new
41
46
 
47
+ CADR = /^c([ad]+)r$/
48
+
49
+ def first
50
+ head
51
+ end
52
+
42
53
  def empty?
43
54
  false
44
55
  end
45
- alias_method :null?, :empty?
56
+ def_delegator :self, :empty?, :null?
46
57
 
47
58
  def size
48
59
  reduce(0) { |memo, item| memo.succ }
49
60
  end
50
- alias_method :length, :size
61
+ def_delegator :self, :size, :length
51
62
 
52
63
  def cons(item)
53
64
  Sequence.new(item, self)
54
65
  end
55
- alias_method :>>, :cons
66
+ def_delegator :self, :cons, :>>
56
67
 
57
68
  def each
58
69
  return self unless block_given?
@@ -62,13 +73,19 @@ module Hamster
62
73
  list = list.tail
63
74
  end
64
75
  end
65
- alias_method :foreach, :each
76
+ def_delegator :self, :each, :foreach
66
77
 
67
78
  def map(&block)
68
79
  return self unless block_given?
69
- Stream.new(yield(head)) { tail.map(&block) }
80
+ Stream.new do
81
+ if empty?
82
+ self
83
+ else
84
+ Sequence.new(yield(head), tail.map(&block))
85
+ end
86
+ end
70
87
  end
71
- alias_method :collect, :map
88
+ def_delegator :self, :map, :collect
72
89
 
73
90
  def reduce(memo = Undefined, &block)
74
91
  return tail.reduce(head, &block) if memo.equal?(Undefined)
@@ -76,80 +93,102 @@ module Hamster
76
93
  each { |item| memo = yield(memo, item) }
77
94
  memo
78
95
  end
79
- alias_method :inject, :reduce
80
- alias_method :fold, :reduce
96
+ def_delegator :self, :reduce, :inject
97
+ def_delegator :self, :reduce, :fold
81
98
 
82
99
  def filter(&block)
83
100
  return self unless block_given?
84
- list = self
85
- while !yield(list.head)
86
- list = list.tail
87
- return list if list.empty?
101
+ Stream.new do
102
+ if empty?
103
+ self
104
+ elsif yield(head)
105
+ Sequence.new(head, tail.filter(&block))
106
+ else
107
+ tail.filter(&block)
108
+ end
88
109
  end
89
- Stream.new(list.head) { list.tail.filter(&block) }
90
110
  end
91
- alias_method :select, :filter
92
- alias_method :find_all, :filter
111
+ def_delegator :self, :filter, :select
112
+ def_delegator :self, :filter, :find_all
93
113
 
94
114
  def remove(&block)
95
115
  return self unless block_given?
96
116
  filter { |item| !yield(item) }
97
117
  end
98
- alias_method :reject, :remove
99
- alias_method :delete_if, :remove
118
+ def_delegator :self, :remove, :reject
119
+ def_delegator :self, :remove, :delete_if
100
120
 
101
121
  def take_while(&block)
102
122
  return self unless block_given?
103
- if yield(head)
104
- Stream.new(head) { tail.take_while(&block) }
105
- else
106
- EmptyList
123
+ Stream.new do
124
+ if empty?
125
+ self
126
+ elsif yield(head)
127
+ Sequence.new(head, tail.take_while(&block))
128
+ else
129
+ EmptyList
130
+ end
107
131
  end
108
132
  end
109
133
 
110
- def drop_while
134
+ def drop_while(&block)
111
135
  return self unless block_given?
112
- list = self
113
- while !list.empty? && yield(list.head)
114
- list = list.tail
136
+ Stream.new do
137
+ if empty?
138
+ self
139
+ elsif yield(head)
140
+ tail.drop_while(&block)
141
+ else
142
+ self
143
+ end
115
144
  end
116
- list
117
145
  end
118
146
 
119
147
  def take(number)
120
- return EmptyList unless number > 0
121
- Stream.new(head) { tail.take(number - 1) }
148
+ Stream.new do
149
+ if empty?
150
+ self
151
+ elsif number > 0
152
+ Sequence.new(head, tail.take(number - 1))
153
+ else
154
+ EmptyList
155
+ end
156
+ end
122
157
  end
123
158
 
124
159
  def drop(number)
125
- list = self
126
- while !list.empty? && number > 0
127
- number -= 1
128
- list = list.tail
160
+ Stream.new do
161
+ if empty?
162
+ self
163
+ elsif number > 0
164
+ tail.drop(number - 1)
165
+ else
166
+ self
167
+ end
129
168
  end
130
- list
131
169
  end
132
170
 
133
171
  def include?(object)
134
172
  any? { |item| item == object }
135
173
  end
136
- alias_method :member?, :include?
137
- alias_method :contains?, :include?
138
- alias_method :elem?, :include?
174
+ def_delegator :self, :include?, :member?
175
+ def_delegator :self, :include?, :contains?
176
+ def_delegator :self, :include?, :elem?
139
177
 
140
178
  def any?
141
179
  return any? { |item| item } unless block_given?
142
180
  each { |item| return true if yield(item) }
143
181
  false
144
182
  end
145
- alias_method :exist?, :any?
146
- alias_method :exists?, :any?
183
+ def_delegator :self, :any?, :exist?
184
+ def_delegator :self, :any?, :exists?
147
185
 
148
186
  def all?
149
187
  return all? { |item| item } unless block_given?
150
188
  each { |item| return false unless yield(item) }
151
189
  true
152
190
  end
191
+ def_delegator :self, :all?, :forall?
153
192
 
154
193
  def none?
155
194
  return none? { |item| item } unless block_given?
@@ -171,19 +210,25 @@ module Hamster
171
210
  return nil unless block_given?
172
211
  each { |item| return item if yield(item) }
173
212
  end
174
- alias_method :detect, :find
213
+ def_delegator :self, :find, :detect
175
214
 
176
215
  def partition(&block)
177
216
  return self unless block_given?
178
- Stream.new(filter(&block)) { Sequence.new(remove(&block)) }
217
+ Stream.new { Sequence.new(filter(&block), Sequence.new(remove(&block))) }
179
218
  end
180
219
 
181
220
  def append(other)
182
- Stream.new(head) { tail.append(other) }
221
+ Stream.new do
222
+ if empty?
223
+ other
224
+ else
225
+ Sequence.new(head, tail.append(other))
226
+ end
227
+ end
183
228
  end
184
- alias_method :concat, :append
185
- alias_method :cat, :append
186
- alias_method :+, :append
229
+ def_delegator :self, :append, :concat
230
+ def_delegator :self, :append, :cat
231
+ def_delegator :self, :append, :+
187
232
 
188
233
  def reverse
189
234
  reduce(EmptyList) { |list, item| list.cons(item) }
@@ -193,37 +238,49 @@ module Hamster
193
238
  return minimum { |minimum, item| item <=> minimum } unless block_given?
194
239
  reduce { |minimum, item| yield(minimum, item) < 0 ? item : minimum }
195
240
  end
196
- alias_method :min, :minimum
241
+ def_delegator :self, :minimum, :min
197
242
 
198
243
  def maximum(&block)
199
244
  return maximum { |maximum, item| item <=> maximum } unless block_given?
200
245
  reduce { |maximum, item| yield(maximum, item) > 0 ? item : maximum }
201
246
  end
202
- alias_method :max, :maximum
247
+ def_delegator :self, :maximum, :max
203
248
 
204
249
  def grep(pattern, &block)
205
250
  filter { |item| pattern === item }.map(&block)
206
251
  end
207
252
 
208
253
  def zip(other)
209
- Stream.new(Sequence.new(other.head).cons(head)) { tail.zip(other.tail) }
254
+ Stream.new do
255
+ if empty? && other.empty?
256
+ self
257
+ else
258
+ Sequence.new(Sequence.new(head, Sequence.new(other.head)), tail.zip(other.tail))
259
+ end
260
+ end
210
261
  end
211
262
 
212
263
  def cycle
213
- Stream.new(head) { tail.append(self.cycle) }
264
+ Stream.new do
265
+ if empty?
266
+ self
267
+ else
268
+ Sequence.new(head, tail.append(self.cycle))
269
+ end
270
+ end
214
271
  end
215
272
 
216
273
  def split_at(number)
217
- Sequence.new(drop(number)).cons(take(number))
274
+ Sequence.new(take(number), Sequence.new(drop(number)))
218
275
  end
219
276
 
220
277
  def span(&block)
221
- return Sequence.new(EmptyList).cons(self) unless block_given?
222
- Stream.new(take_while(&block)) { Sequence.new(drop_while(&block)) }
278
+ return Sequence.new(self, Sequence.new(EmptyList)) unless block_given?
279
+ Sequence.new(take_while(&block), Sequence.new(drop_while(&block)))
223
280
  end
224
281
 
225
282
  def break(&block)
226
- return Sequence.new(EmptyList).cons(self) unless block_given?
283
+ return Sequence.new(self, Sequence.new(EmptyList)) unless block_given?
227
284
  span { |item| !yield(item) }
228
285
  end
229
286
 
@@ -236,42 +293,56 @@ module Hamster
236
293
  end
237
294
 
238
295
  def sort(&block)
239
- Hamster.list(*to_a.sort(&block))
296
+ Stream.new do
297
+ Hamster.list(*to_a.sort(&block))
298
+ end
240
299
  end
241
300
 
242
301
  def sort_by(&block)
243
302
  return sort unless block_given?
244
- Hamster.list(*to_a.sort_by(&block))
303
+ Stream.new do
304
+ Hamster.list(*to_a.sort_by(&block))
305
+ end
245
306
  end
246
307
 
247
308
  def join(sep = "")
309
+ return "" if empty?
248
310
  sep = sep.to_s
249
311
  tail.reduce(head.to_s) { |string, item| string << sep << item.to_s }
250
312
  end
251
313
 
252
314
  def intersperse(sep)
253
- return self if tail.empty?
254
- Stream.new(head) { Stream.new(sep) { tail.intersperse(sep) } }
315
+ Stream.new do
316
+ if tail.empty?
317
+ self
318
+ else
319
+ Sequence.new(head, Sequence.new(sep, tail.intersperse(sep)))
320
+ end
321
+ end
255
322
  end
256
323
 
257
324
  def uniq(items = Set.new)
258
- list = self
259
- while !list.empty? && items.include?(list.head)
260
- list = list.tail
325
+ Stream.new do
326
+ if empty?
327
+ self
328
+ elsif items.include?(head)
329
+ tail.uniq(items)
330
+ else
331
+ Sequence.new(head, tail.uniq(items.add(head)))
332
+ end
261
333
  end
262
- return list if list.empty?
263
- Stream.new(list.head) { list.tail.uniq(items.add(list.head)) }
264
334
  end
265
- alias_method :nub, :uniq
335
+ def_delegator :self, :uniq, :nub
336
+ def_delegator :self, :uniq, :remove_duplicates
266
337
 
267
338
  def union(other)
268
339
  self.append(other).uniq
269
340
  end
270
- alias_method :|, :union
341
+ def_delegator :self, :union, :|
271
342
 
272
343
  def init
273
344
  return EmptyList if tail.empty?
274
- Stream.new(head) { tail.init }
345
+ Stream.new { Sequence.new(head, tail.init) }
275
346
  end
276
347
 
277
348
  def last
@@ -290,6 +361,38 @@ module Hamster
290
361
  reduce(0, &:+)
291
362
  end
292
363
 
364
+ def tails
365
+ Stream.new do
366
+ if empty?
367
+ Sequence.new(self)
368
+ else
369
+ Sequence.new(self, tail.tails)
370
+ end
371
+ end
372
+ end
373
+
374
+ def inits
375
+ Stream.new do
376
+ if empty?
377
+ Sequence.new(self)
378
+ else
379
+ Sequence.new(EmptyList, tail.inits.map { |list| list.cons(head) })
380
+ end
381
+ end
382
+ end
383
+
384
+ def combinations(number)
385
+ return Sequence.new(EmptyList) if number == 0
386
+ Stream.new do
387
+ if empty?
388
+ self
389
+ else
390
+ tail.combinations(number - 1).map { |list| list.cons(head) }.append(tail.combinations(number))
391
+ end
392
+ end
393
+ end
394
+ def_delegator :self, :combinations, :combination
395
+
293
396
  def eql?(other)
294
397
  return false unless other.is_a?(List)
295
398
 
@@ -301,20 +404,21 @@ module Hamster
301
404
  list = list.tail
302
405
  other = other.tail
303
406
  end
304
- other.equal?(list)
407
+
408
+ other.empty? && list.empty?
305
409
  end
306
- alias_method :==, :eql?
410
+ def_delegator :self, :eql?, :==
307
411
 
308
412
  def dup
309
413
  self
310
414
  end
311
- alias_method :clone, :dup
415
+ def_delegator :self, :dup, :clone
312
416
 
313
417
  def to_a
314
418
  reduce([]) { |a, item| a << item }
315
419
  end
316
- alias_method :to_ary, :to_a
317
- alias_method :entries, :to_a
420
+ def_delegator :self, :to_a, :to_ary
421
+ def_delegator :self, :to_a, :entries
318
422
 
319
423
  def to_list
320
424
  self
@@ -324,10 +428,14 @@ module Hamster
324
428
  to_a.inspect
325
429
  end
326
430
 
431
+ def respond_to?(name, include_private = false)
432
+ super || CADR === name
433
+ end
434
+
327
435
  private
328
436
 
329
437
  def method_missing(name, *args, &block)
330
- if name.to_s =~ /^c([ad]+)r$/
438
+ if CADR === name
331
439
  accessor($1)
332
440
  else
333
441
  super
@@ -354,7 +462,6 @@ module Hamster
354
462
  include List
355
463
 
356
464
  attr_reader :head, :tail
357
- alias_method :first, :head
358
465
 
359
466
  def initialize(head, tail = EmptyList)
360
467
  @head = head
@@ -367,22 +474,33 @@ module Hamster
367
474
 
368
475
  include List
369
476
 
370
- attr_reader :head
371
- alias_method :first, :head
372
-
373
- def initialize(head, &tail)
374
- @head = head
375
- @tail = tail
477
+ def initialize(&block)
478
+ @block = block
376
479
  @mutex = Mutex.new
377
480
  end
378
481
 
482
+ def head
483
+ target.head
484
+ end
485
+
379
486
  def tail
487
+ target.tail
488
+ end
489
+
490
+ def empty?
491
+ target.empty?
492
+ end
493
+
494
+ private
495
+
496
+ def target
380
497
  @mutex.synchronize do
381
- unless defined?(@value)
382
- @value = @tail.call
498
+ unless defined?(@target)
499
+ @target = @block.call
500
+ @block = nil
383
501
  end
384
502
  end
385
- @value
503
+ @target
386
504
  end
387
505
 
388
506
  end
@@ -396,7 +514,6 @@ module Hamster
396
514
  def head
397
515
  nil
398
516
  end
399
- alias_method :first, :head
400
517
 
401
518
  def tail
402
519
  self
@@ -405,48 +522,6 @@ module Hamster
405
522
  def empty?
406
523
  true
407
524
  end
408
- alias_method :null?, :empty?
409
-
410
- def map
411
- self
412
- end
413
- alias_method :collect, :map
414
-
415
- def filter
416
- self
417
- end
418
- alias_method :select, :filter
419
- alias_method :find_all, :filter
420
-
421
- def remove
422
- self
423
- end
424
- alias_method :reject, :remove
425
- alias_method :delete_if, :remove
426
-
427
- def take_while
428
- self
429
- end
430
-
431
- def take(number)
432
- self
433
- end
434
-
435
- def append(other)
436
- other
437
- end
438
- alias_method :concat, :append
439
- alias_method :cat, :append
440
- alias_method :+, :append
441
-
442
- def zip(other)
443
- return super unless other.empty?
444
- self
445
- end
446
-
447
- def cycle
448
- self
449
- end
450
525
 
451
526
  end
452
527