Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will last of a lazy seq evaluate all elements in clojure?

Let's assume that we have an expensive computation expensive. If we consider that map produces a lazy seq, then does the following evaluate the function expensive for all elements of the mapped collection or only for the last one?

(last
  (map expensive '(1 2 3 4 5)))

I.e. does this evaluate expensive for all the values 1..5 or does it only evaluate (expensive 5)?

like image 409
lhahne Avatar asked Dec 21 '22 05:12

lhahne


2 Answers

The whole collection will be evaluated. A simple test answers your question.

=> (defn exp [x]
     (println "ran")
     x)
=> (last
     (map exp '(1 2 3 4 5)))
ran
ran
ran
ran
ran
5
like image 134
Paul Lam Avatar answered Dec 30 '22 22:12

Paul Lam


There is no random access for lazy sequences in Clojure.

In a way, you can consider them equivalent to singly linked lists - you always have the current element and a function to get the next one.

So, even if you just call (last some-seq) it will evaluate all the sequence elements even if the sequence is lazy.If the sequence is finite and reasonably small (and if you don't hold the head of the sequence in a reference) it's fine when it comes to memory. As you noted, there is a problem with execution time that may occur if the function used to get the next element is expensive.

In that case, you can make a compromise so that you use a cheap function to walk all the way to the last element:

(last some-seq)

and then apply the function only on that result:

(expensive (last some-seq))

like image 30
Goran Jovic Avatar answered Dec 30 '22 23:12

Goran Jovic