Search code examples
functionvectorclojureread-eval-print-loop

Clojure, musings on some function


I'm playing around at the repl (lein-repl and light table) and have noticed something odd about using the some function:

(def my-vec [5 :test])
(some even? my-vec)     
;=>  java.lang.IllegalArgumentException: Argument must be an integer: :test
;            core.clj:1351 clojure.core/even?
;            core.clj:2515 clojure.core/some

(some odd? my-vec)      ;=> true
(some integer? my-vec)  ;=> true
(some map? my-vec)      ;=> nil

(def my-vec2 [4 :test])
(some even? my-vec2)     ;=> true
(some odd? my-vec2) 
;=> java.lang.IllegalArgumentException: Argument must be an integer: :test
;            core.clj:1351 clojure.core/even?
;            core.clj:1357 clojure.core/odd?
;            core.clj:2515 clojure.core/some

(some integer? my-vec)  ;=> true
(some map? my-vec)      ;=> nil

The doc for some says:

some
clojure.core
([pred coll])
Returns the first logical true value of (pred x) for any x in coll,
  else nil.  One common idiom is to use a set as pred, for example
  this will return :fred if :fred is in the sequence, otherwise nil:
  (some #{:fred} coll)

Why do I get an error about integers with odd?/even? when it's not in the vector? Shouldn't it return nil, instead?


Solution

  • Some will apply the predicate to each element of the collection until it gets a truthy value.

    In the case of

    (some even? [5 :test])
    

    some will try

    (even? 5) ;=> false
    

    and then

    (even? :test) ;=> Exception...
    

    since even? requires an integer.

    Try instead

    (some (every-pred integer? even?) [5 :test])
    ;=> nil
    
    (some (every-pred integer? even?) [5 6 :test])
    ;=> true