@@ -5,6 +5,8 @@ defrecord Range, [:first, :last] do
55end
66
77defprotocol Range.Iterator do
8+ def reduce ( first , range , acc , fun )
9+
810 @ doc """
911 How to iterate the range, receives the first
1012 and range as arguments. It needs to return a
@@ -21,6 +23,10 @@ defprotocol Range.Iterator do
2123end
2224
2325defimpl Enum.Iterator , for: Range do
26+ def reduce ( Range [ first : first ] = range , acc , fun ) do
27+ Range.Iterator . reduce ( first , range , acc , fun )
28+ end
29+
2430 def iterator ( Range [ first : first ] = range ) do
2531 iterator = Range.Iterator . iterator ( first , range )
2632 { iterator , iterator . ( first ) }
@@ -36,6 +42,31 @@ defimpl Enum.Iterator, for: Range do
3642end
3743
3844defimpl Range.Iterator , for: Number do
45+ def reduce ( first , Range [ last : last ] , acc , fun ) when is_integer ( first ) and is_integer ( last ) do
46+ reducer = if last >= first do
47+ fn ( acc , fun ) -> do_reducer_up ( first , last , acc , fun ) end
48+ else
49+ fn ( acc , fun ) -> do_reducer_down ( first , last , acc , fun ) end
50+ end
51+ Enum.Iterator.Function . reduce ( reducer , acc , fun )
52+ end
53+
54+ defp do_reducer_up ( counter , last , acc , fun ) do
55+ if counter > last do
56+ acc
57+ else
58+ do_reducer_up ( counter + 1 , last , fun . ( counter , acc ) , fun )
59+ end
60+ end
61+
62+ defp do_reducer_down ( counter , last , acc , fun ) do
63+ if counter < last do
64+ acc
65+ else
66+ do_reducer_down ( counter - 1 , last , fun . ( counter , acc ) , fun )
67+ end
68+ end
69+
3970 def iterator ( first , Range [ last : last ] ) when is_integer ( first ) and is_integer ( last ) and last >= first do
4071 fn ( current ) ->
4172 if current > last , do: :stop , else: { current , current + 1 }
0 commit comments