immutable 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,196 @@
1
+ require_relative "stream"
2
+ require_relative "consable"
3
+
4
+ module Immutable
5
+ # +Immutable::Deque+ is an implementation of real-time deques described in
6
+ # "Purely Functional Data Structures" by Chris Okasaki.
7
+ class Deque
8
+ include Consable
9
+
10
+ # +Deque.new+ is for internal use only. Use {Deque.empty} or {Deque.[]}
11
+ # instead.
12
+ def initialize(front, front_len, front_schedule,
13
+ rear, rear_len, rear_schedule)
14
+ @front = front
15
+ @front_len = front_len
16
+ @front_schedule = front_schedule
17
+ @rear = rear
18
+ @rear_len = rear_len
19
+ @rear_schedule = rear_schedule
20
+ @c = 3 # @c should be 2 or 3
21
+ end
22
+
23
+ # Returns an empty deque.
24
+ #
25
+ # @return [Deque] the empty deque.
26
+ def self.empty
27
+ Deque.new(Stream.empty, 0, Stream.empty,
28
+ Stream.empty, 0, Stream.empty)
29
+ end
30
+
31
+ # Creates a new deque populated with the given objects.
32
+ #
33
+ # @param [Array<Object>] elements the elements of the deque.
34
+ # @return [Deque] the new deque.
35
+ def self.[](*elements)
36
+ elements.inject(empty, &:snoc)
37
+ end
38
+
39
+ # Returns whether +self+ is empty.
40
+ #
41
+ # @return [true, false] +true+ if +self+ is empty; otherwise, +false+.
42
+ def empty?
43
+ length == 0
44
+ end
45
+
46
+ # Returns the number of elements in +self+. May be zero.
47
+ #
48
+ # @return [Integer] the number of elements in +self+.
49
+ def length
50
+ @front_len + @rear_len
51
+ end
52
+
53
+ # Adds a new element at the head of +self+.
54
+ #
55
+ # @param [Object] x the element to add.
56
+ # @return [Deque] a new deque.
57
+ def cons(x)
58
+ queue(Stream.cons(->{x}, ->{@front}), @front_len + 1,
59
+ exec1(@front_schedule),
60
+ @rear, @rear_len, exec1(@rear_schedule))
61
+ end
62
+
63
+ # Returns the first element of +self+. If +self+ is empty,
64
+ # +Immutable::EmptyError+ is raised.
65
+ #
66
+ # @return [Object] the first element of +self+.
67
+ def head
68
+ if @front.empty?
69
+ if @rear.empty?
70
+ raise EmptyError
71
+ else
72
+ @rear.head
73
+ end
74
+ else
75
+ @front.head
76
+ end
77
+ end
78
+
79
+ # Returns the elements after the head of +self+. If +self+ is empty,
80
+ # +Immutable::EmptyError+ is raised.
81
+ #
82
+ # @return [Deque] the elements after the head of +self+.
83
+ def tail
84
+ if @front.empty?
85
+ if @rear.empty?
86
+ raise EmptyError
87
+ else
88
+ self.class.empty
89
+ end
90
+ else
91
+ queue(@front.tail, @front_len - 1, exec2(@front_schedule),
92
+ @rear, @rear_len, exec2(@rear_schedule))
93
+ end
94
+ end
95
+
96
+ # Adds a new element at the end of +self+.
97
+ #
98
+ # @param [Object] x the element to add.
99
+ # @return [Deque] a new queue.
100
+ def snoc(x)
101
+ queue(@front, @front_len, exec1(@front_schedule),
102
+ Stream.cons(->{x}, ->{@rear}), @rear_len + 1,
103
+ exec1(@rear_schedule))
104
+ end
105
+
106
+ alias push snoc
107
+
108
+ # Returns the last element of +self+. If +self+ is empty,
109
+ # +Immutable::EmptyError+ is raised.
110
+ #
111
+ # @return [Object] the last element of +self+.
112
+ def last
113
+ if @rear.empty?
114
+ if @front.empty?
115
+ raise EmptyError
116
+ else
117
+ @front.head
118
+ end
119
+ else
120
+ @rear.head
121
+ end
122
+ end
123
+
124
+ # Returns all the elements of +self+ except the last one.
125
+ # If +self+ is empty, +Immutable::EmptyError+ is
126
+ # raised.
127
+ #
128
+ # @return [Deque] the elements of +self+ except the last one.
129
+ def init
130
+ if @rear.empty?
131
+ if @front.empty?
132
+ raise EmptyError
133
+ else
134
+ self.class.empty
135
+ end
136
+ else
137
+ queue(@front, @front_len, exec2(@front_schedule),
138
+ @rear.tail, @rear_len - 1, exec2(@rear_schedule))
139
+ end
140
+ end
141
+
142
+ alias pop init
143
+
144
+ private
145
+
146
+ def exec1(s)
147
+ if s.empty?
148
+ s
149
+ else
150
+ s.tail
151
+ end
152
+ end
153
+
154
+ def exec2(s)
155
+ exec1(exec1(s))
156
+ end
157
+
158
+ def rotate_rev(r, f, a)
159
+ if r.empty?
160
+ f.reverse + a
161
+ else
162
+ Stream.cons(->{r.head},
163
+ ->{rotate_rev(r.tail, f.drop(@c),
164
+ f.take(@c).reverse + a)})
165
+ end
166
+ end
167
+
168
+ def rotate_drop(r, i, f)
169
+ if i < @c
170
+ rotate_rev(r, f.drop(i), Stream.empty)
171
+ else
172
+ x = r.head
173
+ r2 = r.tail
174
+ Stream.cons(->{x}, ->{rotate_drop(r2, i - @c, f.drop(@c))})
175
+ end
176
+ end
177
+
178
+ def queue(f, f_len, f_schedule, r, r_len, r_schedule)
179
+ if f_len > @c * r_len + 1
180
+ i = (f_len + r_len) / 2
181
+ j = (f_len + r_len) - i
182
+ f2 = f.take(i)
183
+ r2 = rotate_drop(r, i, f)
184
+ self.class.new(f2, i, f2, r2, j, r2)
185
+ elsif r_len > @c * f_len + 1
186
+ j = (f_len + r_len) / 2
187
+ i = (f_len + r_len) - j
188
+ f2 = rotate_drop(f, j, r)
189
+ r2 = r.take(j)
190
+ self.class.new(f2, i, f2, r2, j, r2)
191
+ else
192
+ self.class.new(f, f_len, f_schedule, r, r_len, r_schedule)
193
+ end
194
+ end
195
+ end
196
+ end
@@ -1,5 +1,15 @@
1
1
  module Immutable
2
2
  module Foldable
3
+ # Reduces +self+ using +block+ from left to right. +e+ is used as the
4
+ # starting value. A class including +Immutable::Foldable+ must implement
5
+ # this method.
6
+ #
7
+ # @param [Object] e the start value.
8
+ # @return [Object] the reduced value.
9
+ def foldl(e, &block)
10
+ raise NotImplementedError
11
+ end
12
+
3
13
  # Returns the number of elements in +self+. May be zero.
4
14
  #
5
15
  # @return [Integer] the number of elements in +self+.
@@ -0,0 +1,235 @@
1
+ require_relative "foldable"
2
+
3
+ module Immutable
4
+ class EmptyError < StandardError
5
+ def initialize(msg = "collection is empty")
6
+ super(msg)
7
+ end
8
+ end
9
+
10
+ module Headable
11
+ include Enumerable
12
+ include Foldable
13
+
14
+ # Returns the first element of +self+. If +self+ is empty,
15
+ # +Immutable::EmptyError+ is raised. A class including
16
+ # +Immutable::Headable+ must implement this method.
17
+ #
18
+ # @return [Object] the first element of +self+.
19
+ def head
20
+ raise NotImplementedError
21
+ end
22
+
23
+ # Same as {#head}. This method just calls {#head}.
24
+ #
25
+ # @return [Object] the first element of +self+.
26
+ def first
27
+ head
28
+ end
29
+
30
+ # Returns the elements after the head of +self+. If +self+ is empty,
31
+ # +Immutable::EmptyError+ is raised. A class including
32
+ # +Immutable::Headable+ must implement this method.
33
+ #
34
+ # @return [Headable] the elements after the head of +self+.
35
+ def tail
36
+ raise NotImplementedError
37
+ end
38
+
39
+ # Same as {#tail}. This method just calls {#tail}.
40
+ #
41
+ # @return [Headable] the elements after the head of +self+.
42
+ def shift
43
+ tail
44
+ end
45
+
46
+ # Returns whether +self+ is empty. A class including
47
+ # +Immutable::Headable+ must implement this method.
48
+ #
49
+ # @return [true, false] +true+ if +self+ is empty; otherwise, +false+.
50
+ def empty?
51
+ raise NotImplementedError
52
+ end
53
+
54
+ # Same as {#empty?}. This method just calls {#empty?}.
55
+ #
56
+ # @return [true, false] +true+ if +self+ is empty; otherwise, +false+.
57
+ def null?
58
+ empty?
59
+ end
60
+
61
+ # Returns a string containing a human-readable representation of +self+.
62
+ #
63
+ # @return [String] a string representation of +self+.
64
+ def inspect
65
+ if empty?
66
+ class_name + "[]"
67
+ else
68
+ class_name + "[" + head.inspect +
69
+ tail.foldl("") {|x, y| x + ", " + y.inspect } + "]"
70
+ end
71
+ end
72
+
73
+ # Returns whether +self+ equals to +x+.
74
+ #
75
+ # @param [Object] x the object to compare.
76
+ # @return [true, false] +true+ if +self+ equals to +x+; otherwise,
77
+ # +false+.
78
+ def ==(x)
79
+ if !x.is_a?(self.class)
80
+ false
81
+ else
82
+ if empty?
83
+ x.empty?
84
+ else
85
+ !x.empty? && head == x.head && tail == x.tail
86
+ end
87
+ end
88
+ end
89
+
90
+ def eql?(x)
91
+ if !x.is_a?(self.class)
92
+ false
93
+ else
94
+ if empty?
95
+ x.empty?
96
+ else
97
+ !x.empty? && head.eql?(x.head) && tail.eql?(x.tail)
98
+ end
99
+ end
100
+ end
101
+
102
+ # @return [Integer]
103
+ def hash
104
+ to_a.hash
105
+ end
106
+
107
+ # Calls +block+ once for each element in +self+.
108
+ # @yield [element]
109
+ # @yieldreturn [self]
110
+ # @return [Enumerator]
111
+ def each(&block)
112
+ return to_enum unless block_given?
113
+
114
+ unless empty?
115
+ yield(head)
116
+ tail.each(&block)
117
+ end
118
+
119
+ self
120
+ end
121
+
122
+ # Reduces +self+ using +block+ from right to left. +e+ is used as the
123
+ # starting value. For example:
124
+ #
125
+ # List[1, 2, 3].foldr(9) { |x, y| x + y } #=> 1 - (2 - (3 - 9)) = -7
126
+ #
127
+ # @param [Object] e the start value.
128
+ # @return [Object] the reduced value.
129
+ def foldr(e, &block)
130
+ if empty?
131
+ e
132
+ else
133
+ yield(head, tail.foldr(e, &block))
134
+ end
135
+ end
136
+
137
+ # Reduces +self+ using +block+ from right to left. If +self+ is empty,
138
+ # +Immutable::EmptyError+ is raised.
139
+ #
140
+ # @return [Object] the reduced value.
141
+ def foldr1(&block)
142
+ if empty?
143
+ raise EmptyError
144
+ else
145
+ if tail.empty?
146
+ head
147
+ else
148
+ yield(head, tail.foldr1(&block))
149
+ end
150
+ end
151
+ end
152
+
153
+ # Reduces +self+ using +block+ from left to right. +e+ is used as the
154
+ # starting value. For example:
155
+ #
156
+ # List[1, 2, 3].foldl(9) { |x, y| x + y } #=> ((9 - 1) - 2) - 3 = 3
157
+ #
158
+ # @param [Object] e the start value.
159
+ # @return [Object] the reduced value.
160
+ def foldl(e, &block)
161
+ if empty?
162
+ e
163
+ else
164
+ tail.foldl(yield(e, head), &block)
165
+ end
166
+ end
167
+
168
+ # Reduces +self+ using +block+ from left to right. If +self+ is empty,
169
+ # +Immutable::EmptyError+ is raised.
170
+ #
171
+ # @return [Object] the reduced value.
172
+ def foldl1(&block)
173
+ if empty?
174
+ raise EmptyError
175
+ else
176
+ tail.foldl(head, &block)
177
+ end
178
+ end
179
+
180
+ # Returns the first element in +self+ for which the given block
181
+ # evaluates to true. If such an element is not found, it
182
+ # returns +nil+.
183
+ #
184
+ # @param [#call, nil] ifnone
185
+ # @yield [element]
186
+ # @yieldreturn [Object] the found element.
187
+ # @return [Enumerator]
188
+ def find(ifnone=nil, &block)
189
+ return to_enum(__callee__, ifnone) unless block_given?
190
+
191
+ if empty?
192
+ if ifnone.nil?
193
+ nil
194
+ else
195
+ ifnone.call
196
+ end
197
+ else
198
+ if yield(head)
199
+ head
200
+ else
201
+ tail.find(ifnone, &block)
202
+ end
203
+ end
204
+ end
205
+
206
+ alias detect find
207
+
208
+ # Returns the +n+th element of +self+. If +n+ is out of range, +nil+ is
209
+ # returned.
210
+ #
211
+ # @return [Object] the +n+th element.
212
+ def [](n)
213
+ if n < 0 || empty?
214
+ nil
215
+ elsif n == 0
216
+ head
217
+ else
218
+ tail[n - 1]
219
+ end
220
+ end
221
+
222
+ # Converts +self+ to a list.
223
+ #
224
+ # @return [List] a list.
225
+ def to_list
226
+ foldr(List[]) { |x, xs| Cons[x, xs] }
227
+ end
228
+
229
+ private
230
+
231
+ def class_name
232
+ self.class.name.slice(/[^:]*\z/)
233
+ end
234
+ end
235
+ end
@@ -1,4 +1,4 @@
1
- require "immutable/foldable"
1
+ require_relative "consable"
2
2
 
3
3
  module Immutable
4
4
  # +Immutable::List+ represents an immutable list.
@@ -18,82 +18,33 @@ module Immutable
18
18
  # p Nil #=> List[]
19
19
  # p Cons[1, Cons[2, Nil]] #=> List[1, 2]
20
20
  class List
21
- include Enumerable
22
- include Foldable
21
+ include Consable
23
22
 
24
- class EmptyError < StandardError
25
- def initialize(msg = "list is empty")
26
- super(msg)
27
- end
28
- end
29
-
30
- # Creates a new list populated with the given objects.
31
- #
32
- # @param [Array<Object>] elements the elements of the list.
33
- # @return [List] the new list.
34
- def self.[](*elements)
35
- from_array(elements)
36
- end
37
-
38
- # Converts the given array to a list.
39
- #
40
- # @param [Array, #reverse_each] ary the array to convert.
41
- # @return [List] the list converted from +ary+.
42
- def self.from_array(ary)
43
- ary.reverse_each.inject(Nil) { |x, y|
44
- Cons.new(y, x)
45
- }
46
- end
47
-
48
- # Converts the given Enumerable object to a list.
49
- #
50
- # @param [#inject] enum the Enumerable object to convert.
51
- # @return [List] the list converted from +enum+.
52
- def self.from_enum(enum)
53
- enum.inject(Nil) { |x, y|
54
- Cons.new(y, x)
55
- }.reverse
56
- end
57
-
58
- # Calls +block+ once for each element in +self+.
59
- def each(&block)
60
- end
61
-
62
- # Appends two lists +self+ and +xs+.
23
+ # Returns an empty list.
63
24
  #
64
- # @param [List] xs the list to append.
65
- # @return [List] the new list.
66
- def +(xs)
67
- foldr(xs) { |y, ys| Cons[y, ys] }
25
+ # @return [list] the empty list.
26
+ def self.empty
27
+ Nil
68
28
  end
69
29
 
70
- # Returns whether +self+ equals to +xs+.
30
+ # Adds a new element at the head of +self+.
71
31
  #
72
- # @param [List] xs the list to compare.
73
- # @return [true, false] +true+ if +self+ equals to +xs+; otherwise,
74
- # +false+.
75
- def ==(xs)
76
- # this method should be overriden
32
+ # @param [Object] x the element to add.
33
+ # @return [List] a new list.
34
+ def cons(x)
35
+ Cons[x, self]
77
36
  end
78
37
 
79
38
  # Returns the first element of +self+. If +self+ is empty,
80
- # +Immutable::List::EmptyError+ is raised.
39
+ # +Immutable::EmptyError+ is raised.
81
40
  #
82
41
  # @return [Object] the first element of +self+.
83
42
  def head
84
43
  # this method should be overriden
85
44
  end
86
45
 
87
- # Returns the first element of +self+. If +self+ is empty,
88
- # +Immutable::List::EmptyError+ is raised.
89
- #
90
- # @return [Object] the first element of +self+.
91
- def first
92
- head
93
- end
94
-
95
46
  # Returns the last element of +self+. If +self+ is empty,
96
- # +Immutable::List::EmptyError+ is raised.
47
+ # +Immutable::EmptyError+ is raised.
97
48
  #
98
49
  # @return [Object] the last element of +self+.
99
50
  def last
@@ -101,7 +52,7 @@ module Immutable
101
52
  end
102
53
 
103
54
  # Returns the elements after the head of +self+. If +self+ is empty,
104
- # +Immutable::List::EmptyError+ is raised.
55
+ # +Immutable::EmptyError+ is raised.
105
56
  #
106
57
  # @return [List] the elements after the head of +self+.
107
58
  def tail
@@ -109,7 +60,7 @@ module Immutable
109
60
  end
110
61
 
111
62
  # Returns all the elements of +self+ except the last one.
112
- # If +self+ is empty, +Immutable::List::EmptyError+ is
63
+ # If +self+ is empty, +Immutable::EmptyError+ is
113
64
  # raised.
114
65
  #
115
66
  # @return [List] the elements of +self+ except the last one.
@@ -117,193 +68,17 @@ module Immutable
117
68
  # this method should be overriden
118
69
  end
119
70
 
120
- # Returns whether +self+ is empty.
71
+ # Same as {#init}.
121
72
  #
122
- # @return [true, false] +true+ if +self+ is empty; otherwise, +false+.
123
- def empty?
124
- # this method should be overriden
73
+ # @return [List] the elements of +self+ except the last one.
74
+ def pop
75
+ init
125
76
  end
126
77
 
127
78
  # Returns whether +self+ is empty.
128
79
  #
129
80
  # @return [true, false] +true+ if +self+ is empty; otherwise, +false+.
130
- def null?
131
- empty?
132
- end
133
-
134
- # Returns the list obtained by applying the given block to each element
135
- # in +self+.
136
- #
137
- # @return [List] the obtained list.
138
- def map
139
- foldr(Nil) { |x, xs| Cons[yield(x), xs] }
140
- end
141
-
142
- # Returns the elements of +self+ in reverse order.
143
- #
144
- # @return [List] the reversed list.
145
- def reverse
146
- foldl(Nil) { |x, y| Cons[y, x] }
147
- end
148
-
149
- # Returns a new list obtained by inserting +sep+ in between the elements
150
- # of +self+.
151
- #
152
- # @param [Object] sep the object to insert between elements.
153
- # @return [List] the new list.
154
- def intersperse(sep)
155
- # this method should be overriden
156
- end
157
-
158
- # Returns a new list obtained by inserting +xs+ in between the lists in
159
- # +self+ and concatenates the result.
160
- # +xss.intercalate(xs)+ is equivalent to
161
- # +xss.intersperse(xs).flatten+.
162
- #
163
- # @param [List] xs the list to insert between lists.
164
- # @return [List] the new list.
165
- def intercalate(xs)
166
- intersperse(xs).flatten
167
- end
168
-
169
- # Transposes the rows and columns of +self+. For example:
170
- #
171
- # p List[List[1, 2, 3], List[4, 5, 6]].transpose
172
- # #=> List[List[1, 4], List[2, 5], List[3, 6]]
173
- #
174
- # @return [List] the transposed list.
175
- def transpose
176
- # this method should be overriden
177
- end
178
-
179
- # Returns the list of all subsequences of +self+.
180
- #
181
- # @return [List<List>] the list of subsequences.
182
- def subsequences
183
- Cons[List[], nonempty_subsequences]
184
- end
185
-
186
- # Reduces +self+ using +block+ from right to left. +e+ is used as the
187
- # starting value. For example:
188
- #
189
- # List[1, 2, 3].foldr(9) { |x, y| x + y } #=> 1 - (2 - (3 - 9)) = -7
190
- #
191
- # @param [Object] e the start value.
192
- # @return [Object] the reduced value.
193
- def foldr(e, &block)
194
- # this method should be overriden
195
- end
196
-
197
- # Reduces +self+ using +block+ from right to left. If +self+ is empty,
198
- # +Immutable::List::EmptyError+ is raised.
199
- #
200
- # @return [Object] the reduced value.
201
- def foldr1(&block)
202
- # this method should be overriden
203
- end
204
-
205
- # Reduces +self+ using +block+ from left to right. +e+ is used as the
206
- # starting value. For example:
207
- #
208
- # List[1, 2, 3].foldl(9) { |x, y| x + y } #=> ((9 - 1) - 2) - 3 = 3
209
- #
210
- # @param [Object] e the start value.
211
- # @return [Object] the reduced value.
212
- def foldl(e, &block)
213
- # this method should be overriden
214
- end
215
-
216
- # Reduces +self+ using +block+ from left to right. If +self+ is empty,
217
- # +Immutable::List::EmptyError+ is raised.
218
- #
219
- # @return [Object] the reduced value.
220
- def foldl1(&block)
221
- # this method should be overriden
222
- end
223
-
224
- # Concatenates a list of lists.
225
- #
226
- # @return [List] the concatenated list.
227
- def flatten
228
- foldr(Nil) { |x, xs| x + xs }
229
- end
230
-
231
- alias concat flatten
232
-
233
- # Returns the list obtained by concatenating the results of the given
234
- # block for each element in +self+.
235
- #
236
- # @return [List] the obtained list.
237
- def flat_map
238
- foldr(Nil) { |x, xs| yield(x) + xs }
239
- end
240
-
241
- alias concat_map flat_map
242
-
243
- alias bind flat_map
244
-
245
- # Builds a list from the seed value +e+ and the given block. The block
246
- # takes a seed value and returns +nil+ if the seed should
247
- # unfold to the empty list, or returns +[a, b]+, where
248
- # +a+ is the head of the list and +b+ is the next
249
- # seed from which to unfold the tail. For example:
250
- #
251
- # xs = List.unfoldr(3) { |x| x == 0 ? nil : [x, x - 1] }
252
- # p xs #=> List[3, 2, 1]
253
- #
254
- # +unfoldr+ is the dual of +foldr+.
255
- #
256
- # @param [Object] e the seed value.
257
- # @return [List] the list built from the seed value and the block.
258
- def self.unfoldr(e, &block)
259
- x = yield(e)
260
- if x.nil?
261
- Nil
262
- else
263
- y, z = x
264
- Cons[y, unfoldr(z, &block)]
265
- end
266
- end
267
-
268
- # Returns the +n+th element of +self+. If +n+ is out of range, +nil+ is
269
- # returned.
270
- #
271
- # @return [Object] the +n+th element.
272
- def [](n)
273
- # this method should be overriden
274
- end
275
-
276
- # Returns the first +n+ elements of +self+, or all the elements of
277
- # +self+ if +n > self.length+.
278
- #
279
- # @param [Integer] n the number of elements to take.
280
- # @return [List] the first +n+ elements of +self+.
281
- def take(n)
282
- # this method should be overriden
283
- end
284
-
285
- # Returns the suffix of +self+ after the first +n+ elements, or
286
- # +List[]+ if +n > self.length+.
287
- #
288
- # @param [Integer] n the number of elements to drop.
289
- # @return [List] the suffix of +self+ after the first +n+ elements.
290
- def drop(n)
291
- # this method should be overriden
292
- end
293
-
294
- # Returns the longest prefix of the elements of +self+ for which +block+
295
- # evaluates to true.
296
- #
297
- # @return [List] the prefix of the elements of +self+.
298
- def take_while(&block)
299
- # this method should be overriden
300
- end
301
-
302
- # Returns the suffix remaining after
303
- # +self.take_while(&block)+.
304
- #
305
- # @return [List] the suffix of the elements of +self+.
306
- def drop_while(&block)
81
+ def empty?
307
82
  # this method should be overriden
308
83
  end
309
84
 
@@ -314,49 +89,10 @@ module Immutable
314
89
  self
315
90
  end
316
91
 
317
- # Returns the first element in +self+ for which the given block
318
- # evaluates to true. If such an element is not found, it
319
- # returns +nil+.
320
- #
321
- # @return [Object] the found element.
322
- def find(&block)
323
- # this method should be overriden
324
- end
325
-
326
- # Returns the elements in +self+ for which the given block evaluates to
327
- # true.
328
- #
329
- # @return [List] the elements that satisfies the condition.
330
- def filter
331
- foldr(Nil) { |x, xs|
332
- if yield(x)
333
- Cons[x, xs]
334
- else
335
- xs
336
- end
337
- }
338
- end
92
+ private
339
93
 
340
- # Takes zero or more lists and returns a new list in which each element
341
- # is an array of the corresponding elements of +self+ and the input
342
- # lists.
343
- #
344
- # @param [Array<List>] xss the input lists.
345
- # @return [List] the new list.
346
- def zip(*xss)
347
- # this method should be overriden
348
- end
349
-
350
- # Takes zero or more lists and returns the list obtained by applying the
351
- # given block to an array of the corresponding elements of +self+ and
352
- # the input lists.
353
- # +xs.zip_with(*yss, &block)+ is equivalent to
354
- # +xs.zip(*yss).map(&block)+.
355
- #
356
- # @param [Array<List>] xss the input lists.
357
- # @return [List] the new list.
358
- def zip_with(*xss, &block)
359
- # this method should be overriden
94
+ def class_name
95
+ "List"
360
96
  end
361
97
  end
362
98
 
@@ -421,205 +157,5 @@ module Immutable
421
157
  def empty?
422
158
  false
423
159
  end
424
-
425
- def Nil.foldr(e)
426
- e
427
- end
428
-
429
- def foldr(e, &block)
430
- yield(@head, @tail.foldr(e, &block))
431
- end
432
-
433
- def Nil.foldr1
434
- raise EmptyError
435
- end
436
-
437
- def foldr1(&block)
438
- if @tail.empty?
439
- @head
440
- else
441
- yield(@head, @tail.foldr1(&block))
442
- end
443
- end
444
-
445
- def Nil.each
446
- end
447
-
448
- def each(&block)
449
- yield(@head)
450
- @tail.each(&block)
451
- end
452
-
453
- def Nil.foldl(e)
454
- e
455
- end
456
-
457
- def foldl(e, &block)
458
- @tail.foldl(yield(e, @head), &block)
459
- end
460
-
461
- def Nil.foldl1
462
- raise EmptyError
463
- end
464
-
465
- def foldl1(&block)
466
- @tail.foldl(@head, &block)
467
- end
468
-
469
- def Nil.==(xs)
470
- equal?(xs)
471
- end
472
-
473
- def ==(xs)
474
- if !xs.is_a?(List) || xs.empty?
475
- false
476
- else
477
- @head == xs.head && @tail == xs.tail
478
- end
479
- end
480
-
481
- def Nil.inspect
482
- "List[]"
483
- end
484
-
485
- def inspect
486
- "List[" + @head.inspect +
487
- @tail.foldl("") {|x, y| x + ", " + y.inspect } + "]"
488
- end
489
-
490
- def Nil.intersperse(sep)
491
- Nil
492
- end
493
-
494
- def intersperse(sep)
495
- Cons[@head, @tail.prepend_to_all(sep)]
496
- end
497
-
498
- def Nil.prepend_to_all(sep)
499
- Nil
500
- end
501
-
502
- def prepend_to_all(sep)
503
- Cons[sep, Cons[@head, @tail.prepend_to_all(sep)]]
504
- end
505
-
506
- def Nil.transpose
507
- Nil
508
- end
509
-
510
- def transpose
511
- if @head == Nil
512
- @tail.transpose
513
- else
514
- tail = @tail.filter { |x| !x.empty? }
515
- Cons[Cons[@head.head, tail.map(&:head)],
516
- Cons[@head.tail, tail.map(&:tail)].transpose]
517
- end
518
- end
519
-
520
- def Nil.nonempty_subsequences
521
- List[]
522
- end
523
-
524
- def nonempty_subsequences
525
- yss = @tail.nonempty_subsequences.foldr(List[]) { |xs, xss|
526
- Cons[xs, Cons[Cons[@head, xs], xss]]
527
- }
528
- Cons[List[@head], yss]
529
- end
530
-
531
- def Nil.[](n)
532
- nil
533
- end
534
-
535
- def [](n)
536
- if n < 0
537
- nil
538
- elsif n == 0
539
- head
540
- else
541
- tail[n - 1]
542
- end
543
- end
544
-
545
- def Nil.take(n)
546
- Nil
547
- end
548
-
549
- def take(n)
550
- if n <= 0
551
- Nil
552
- else
553
- Cons[@head, @tail.take(n - 1)]
554
- end
555
- end
556
-
557
- def Nil.take_while
558
- Nil
559
- end
560
-
561
- def take_while(&block)
562
- if yield(@head)
563
- Cons[@head, @tail.take_while(&block)]
564
- else
565
- Nil
566
- end
567
- end
568
-
569
- def Nil.drop(n)
570
- Nil
571
- end
572
-
573
- def drop(n)
574
- if n > 0
575
- @tail.drop(n - 1)
576
- else
577
- self
578
- end
579
- end
580
-
581
- def Nil.drop_while
582
- Nil
583
- end
584
-
585
- def drop_while(&block)
586
- if yield(@head)
587
- @tail.drop_while(&block)
588
- else
589
- self
590
- end
591
- end
592
-
593
- def Nil.find
594
- nil
595
- end
596
-
597
- def find(&block)
598
- if yield(@head)
599
- @head
600
- else
601
- @tail.find(&block)
602
- end
603
- end
604
-
605
- def Nil.zip(*xss)
606
- Nil
607
- end
608
-
609
- def zip(*xss)
610
- heads = xss.map { |xs| xs.null? ? nil : xs.head }
611
- tails = xss.map { |xs| xs.null? ? Nil : xs.tail }
612
- Cons[[head, *heads], tail.zip(*tails)]
613
- end
614
-
615
- def Nil.zip_with(*xss, &block)
616
- Nil
617
- end
618
-
619
- def zip_with(*xss, &block)
620
- heads = xss.map { |xs| xs.null? ? nil : xs.head }
621
- tails = xss.map { |xs| xs.null? ? Nil : xs.tail }
622
- Cons[yield(head, *heads), tail.zip_with(*tails, &block)]
623
- end
624
160
  end
625
161
  end