clojure - Why prefer seq over non-empty as a predicate? -
the docstring empty?
says "please use idiom (seq x) rather (not (empty? x))". mistermetaphor points out using seq
predicate can make sense when used in if-let
:
(if-let [s (seq might-be-empty)] (fn-for-non-empty-seq s) (fn-for-empty-seq))
should use seq
test non-emptiness in general, though? seq
may convert argument different form. example:
user=> (class (lazy-seq '(1 2 3))) clojure.lang.lazyseq user=> (class (seq (lazy-seq '(1 2 3)))) clojure.lang.persistentlist user=> (class (map inc [1 2 3])) clojure.lang.lazyseq user=> (class (seq (map inc [1 2 3]))) clojure.lang.chunkedcons
that seems waste of cycles if want test non-emptiness, , don't need new binding, or if don't need conversion before binding. wouldn't not-empty
better choice in such cases? returns nil
if argument empty, , argument unchanged if non-empty.
(if (not-empty []) "more do" "all done")
first, check out definition of empty?
:
(defn empty? "returns true if coll has no items - same (not (seq coll)). please use idiom (seq x) rather (not (empty? x))" {:added "1.0" :static true} [coll] (not (seq coll)))
so empty?
is (not (seq coll))
. that's why it's discouraged complement empty?
, because doing double negation on seq
.
now see not-empty
(defn not-empty "if coll empty, returns nil, else coll" {:added "1.0" :static true} [coll] (when (seq coll) coll))
surprise, uses seq
test of non-emptiness too. not-empty
is useful if type matters -- nth
performance on vectors, conj
behavior, etc. -- because return non-empty colls is. used predicate though, wrapping seq
.
don't worry seq
being heavy-handed though. little more return iterator. not convert entire data structure.
Comments
Post a Comment