immutable 0.2.0 → 0.3.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.
@@ -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