Reputation:
I know there is the reduced
function to terminate such an infinite thing, but i am curious why in the second version (with range
without arg) it doesn't terminate the reduction as it reaches 150?
user=> (reduce (fn [a v] (if (< a 100) (+ a v) a)) (range 2000))
105
user=> (reduce (fn [a v] (if (< a 100) (+ a v) a)) (range))
Upvotes: 2
Views: 149
Reputation: 91554
As you mention, and for those who come along later googling for reduced. The reducing function does have a the ability to declare the final answer of the reduction explicitly with the guarantee that no further input will be consumed by returning the result of calling (reduced the-final-answer)
user> (reduce (fn [a v]
(if (< a 100)
(+ a v)
(reduced a)))
(range))
105
In this case when the new collected result passes 100 the next iteration will stop the reduction rather than contribute it's value to the answer. This does consume one extra value from the input stream that is not included in the result.
user> (reduce (fn [a v]
(let [res (+ a v)]
(if (< res 100)
res
(reduced res))))
(range))
105
This finishes the reduction as soon as threshold is met and does not consume any extra values from the lazy (and infinite) collection.
Upvotes: 4
Reputation: 14197
Because, reduce applies the function to every element in the sequence (range), thus (range) is fully realized.
(range)
produces an infinite sequence, and
(fn [a v] (if (< a 100) (+ a v) a))
doesn't stop the loop, it is being applied to every element.
Executed at the REPL
(reduce (fn [a v] (if (< a 100) (+ a v) a)) (range))
means we eargly wants to get and print the result, therefore the REPL hangs.
Upvotes: 4