@@ -111,15 +111,20 @@ defprotocol Enumerable do
111
111
@ doc """
112
112
Checks if a value exists within the collection.
113
113
114
- Membership should be tested with the match (`===`) operator.
114
+ It should return `{ :ok, boolean }` if membership can be tested
115
+ faster than linear time with the match (`===`) operator, otherwise
116
+ should return `{ :error, __MODULE__ }`.
115
117
"""
116
- @ spec member? ( t , term ) :: boolean
118
+ @ spec member? ( t , term ) :: { :ok , boolean } | { :error , module }
117
119
def member? ( collection , value )
118
120
119
121
@ doc """
120
122
Retrieves the collection's size.
123
+
124
+ Should return `{ :ok, size }` if the size is pre-calculated,
125
+ `{ :error, __MODULE__ }` otherwise.
121
126
"""
122
- @ spec count ( t ) :: non_neg_integer
127
+ @ spec count ( t ) :: { :ok , non_neg_integer } | { :error , module }
123
128
def count ( collection )
124
129
end
125
130
@@ -160,56 +165,6 @@ defmodule Enum do
160
165
@ type index :: non_neg_integer
161
166
@ type default :: any
162
167
163
- @ doc """
164
- Checks if `value` exists within the `collection`.
165
-
166
- Membership is tested with the match (`===`) operator, although
167
- enumerables like ranges may include floats inside the given
168
- range.
169
-
170
- ## Examples
171
-
172
- iex> Enum.member?(1..10, 5)
173
- true
174
- iex> Enum.member?([:a, :b, :c], :d)
175
- false
176
-
177
- """
178
- @ spec member? ( t , element ) :: boolean
179
- def member? ( collection , value ) do
180
- Enumerable . member? ( collection , value )
181
- end
182
-
183
- @ doc """
184
- Returns the collection's size.
185
-
186
- ## Examples
187
-
188
- iex> Enum.count([1, 2, 3])
189
- 3
190
-
191
- """
192
- @ spec count ( t ) :: non_neg_integer
193
- def count ( collection ) do
194
- Enumerable . count ( collection )
195
- end
196
-
197
- @ doc """
198
- Returns the count of items in the collection for which
199
- `fun` returns `true`.
200
-
201
- ## Examples
202
- iex> Enum.count([1, 2, 3, 4, 5], fn(x) -> rem(x, 2) == 0 end)
203
- 2
204
-
205
- """
206
- @ spec count ( t , ( element -> as_boolean ( term ) ) ) :: non_neg_integer
207
- def count ( collection , fun ) do
208
- Enumerable . reduce ( collection , { :cont , 0 } , fn ( entry , acc ) ->
209
- { :cont , if ( fun . ( entry ) , do: acc + 1 , else: acc ) }
210
- end ) |> elem ( 1 )
211
- end
212
-
213
168
@ doc """
214
169
Invokes the given `fun` for each item in the `collection` and returns `false`
215
170
if at least one invocation returns `false`. Otherwise returns `true`.
@@ -352,6 +307,52 @@ defmodule Enum do
352
307
reduce ( enumerable , [ ] , & reduce ( & 1 , & 2 , fun ) ) |> :lists . reverse
353
308
end
354
309
310
+ @ doc """
311
+ Returns the collection's size.
312
+
313
+ ## Examples
314
+
315
+ iex> Enum.count([1, 2, 3])
316
+ 3
317
+
318
+ """
319
+ @ spec count ( t ) :: non_neg_integer
320
+ def count ( collection ) when is_list ( collection ) do
321
+ :erlang . length ( collection )
322
+ end
323
+
324
+ def count ( collection ) do
325
+ case Enumerable . count ( collection ) do
326
+ value when is_integer ( value ) ->
327
+ IO . write "Expected #{ inspect Enumerable . impl_for ( collection ) } .count/1 to return " <>
328
+ "{ :ok, boolean } if pre-calculated, otherwise { :error, module }, got " <>
329
+ "an integer\n #{ Exception . format_stacktrace } "
330
+ value
331
+ { :ok , value } when is_integer ( value ) ->
332
+ value
333
+ { :error , module } ->
334
+ module . reduce ( collection , { :cont , 0 } , fn
335
+ _ , acc -> { :cont , acc + 1 }
336
+ end ) |> elem ( 1 )
337
+ end
338
+ end
339
+
340
+ @ doc """
341
+ Returns the count of items in the collection for which
342
+ `fun` returns `true`.
343
+
344
+ ## Examples
345
+ iex> Enum.count([1, 2, 3, 4, 5], fn(x) -> rem(x, 2) == 0 end)
346
+ 2
347
+
348
+ """
349
+ @ spec count ( t , ( element -> as_boolean ( term ) ) ) :: non_neg_integer
350
+ def count ( collection , fun ) do
351
+ Enumerable . reduce ( collection , { :cont , 0 } , fn ( entry , acc ) ->
352
+ { :cont , if ( fun . ( entry ) , do: acc + 1 , else: acc ) }
353
+ end ) |> elem ( 1 )
354
+ end
355
+
355
356
@ doc """
356
357
Drops the first `count` items from `collection`.
357
358
@@ -841,6 +842,43 @@ defmodule Enum do
841
842
{ :lists . reverse ( list ) , acc }
842
843
end
843
844
845
+ @ doc """
846
+ Checks if `value` exists within the `collection`.
847
+
848
+ Membership is tested with the match (`===`) operator, although
849
+ enumerables like ranges may include floats inside the given
850
+ range.
851
+
852
+ ## Examples
853
+
854
+ iex> Enum.member?(1..10, 5)
855
+ true
856
+ iex> Enum.member?([:a, :b, :c], :d)
857
+ false
858
+
859
+ """
860
+ @ spec member? ( t , element ) :: boolean
861
+ def member? ( collection , value ) when is_list ( collection ) do
862
+ :lists . member ( value , collection )
863
+ end
864
+
865
+ def member? ( collection , value ) do
866
+ case Enumerable . member? ( collection , value ) do
867
+ value when is_boolean ( value ) ->
868
+ IO . write "Expected #{ inspect Enumerable . impl_for ( collection ) } .member?/2 to return " <>
869
+ "{ :ok, boolean } if faster than linear, otherwise { :error, __MODULE__ }, " <>
870
+ "got a boolean\n #{ Exception . format_stacktrace } "
871
+ value
872
+ { :ok , value } when is_boolean ( value ) ->
873
+ value
874
+ { :error , module } ->
875
+ module . reduce ( collection , { :cont , false } , fn
876
+ ^ value , _ -> { :halt , true }
877
+ _ , _ -> { :cont , false }
878
+ end ) |> elem ( 1 )
879
+ end
880
+ end
881
+
844
882
@ doc """
845
883
Partitions `collection` into two collections, where the first one contains elements
846
884
for which `fun` returns a truthy value, and the second one -- for which `fun`
@@ -1952,25 +1990,17 @@ defimpl Enumerable, for: List do
1952
1990
def reduce ( [ ] , { :cont , acc } , _fun ) , do: { :done , acc }
1953
1991
def reduce ( [ h | t ] , { :cont , acc } , fun ) , do: reduce ( t , fun . ( h , acc ) , fun )
1954
1992
1955
- def member? ( [ ] , _ ) , do: false
1956
- def member? ( list , value ) , do: :lists . member ( value , list )
1957
-
1958
- def count ( list ) , do: length ( list )
1993
+ def member? ( _list , _value ) ,
1994
+ do: { :error , __MODULE__ }
1995
+ def count ( _list ) ,
1996
+ do: { :error , __MODULE__ }
1959
1997
end
1960
1998
1961
1999
defimpl Enumerable , for: Function do
1962
- def reduce ( function , acc , fun ) do
1963
- function . ( acc , fun )
1964
- end
1965
-
1966
- def member? ( function , value ) do
1967
- function . ( { :cont , false } , fn
1968
- ^ value , _ -> { :halt , true }
1969
- _ , _ -> { :cont , false }
1970
- end ) |> elem ( 1 )
1971
- end
1972
-
1973
- def count ( function ) do
1974
- function . ( { :cont , 0 } , fn ( _ , acc ) -> { :cont , acc + 1 } end ) |> elem ( 1 )
1975
- end
2000
+ def reduce ( function , acc , fun ) ,
2001
+ do: function . ( acc , fun )
2002
+ def member? ( _function , _value ) ,
2003
+ do: { :error , __MODULE__ }
2004
+ def count ( _function ) ,
2005
+ do: { :error , __MODULE__ }
1976
2006
end
0 commit comments