I'm probably just spacing here, but...
Why is this lazy?
(first (map #(System/getenv %) '("HOME" 42))) => "/home/joe"
But this isn't?
(first (map #(System/getenv %) ["HOME" 42])) => ClassCastException: Long cannot be cast to String
Something about the vector type that prevents laziness?
if you want a lazier (afaik it will always compute only the one result in all standard collections) first with map you can turn to reduction
(defn -first-reducer
([out] out)
([_miss first] (reduced first)))
(defn rfirst
([xs] (rfirst nil xs))
([miss xs] (reduce -first-reducer miss xs))
([xf miss xs] (transduce xf -first-reducer miss xs)))I believe it's because seq on the vector returns a chunked seq, whereas seq on the list does not, and map realizes a chunk at a time (more or less) when seq on coll is chunked.
Ah, yes! Chunking! That explains it! The full vector just happens to fit in one chunk.
> IIRC this is an implementation detail that shouldn't be depended on this is correct, and laziness is rarely the right choice for preventing execution, lazy things are allowed not to evaluate but never promise not to. vectors are not the only source of chunking for example.
(first (map (fn [x]
(println x)
x)
(range 33)))Note that as Bob B said, although you asked for the first element, the 32 first are evaluated. 0 up to 31 in the example, 33rd element (aka 32) is not displayed.
IIRC this is an implementation detail that shouldn't be depended on
As a rule, if you want laziness/"just a list of stuff", opt for sequences- vectors are best for when you care about specific locations of your elements (i.e., tuples, kv-pairs (try and run (into [] {:one 2, :three 4})), etc)