Every once in a while someone asks on the Clojure group
why (contains? [:a :b :c] :a)
returns false
. In the following heated
discussions about semantics (yeah! a discussion about semantics!) people
always suggest to add a linear-search
to Clojure. What they miss:
linear-search
is already there.
The confusion with contains?
is explained quite simply: people expect
it to work on keys with maps and on values with vectors.
; Matches expectations
user=> (contains? {:a 1 :b 2 :c 3} :a)
true
; Surprises people
user=> (contains? [:a :b :c] :a)
false
; More surprised looks
user=> (contains? [:a :b :c] 0)
true
However, reading the last sentence of the previous paragraph should
already explain the above behaviour: vectors are keyed by number,
not the item value! So how can contains?
work as people expect
without being completely inconsistent with its contract?
So contains?
does not a linear search. However another function does:
some
. A perfectly normal, idiomatic Clojure version of the desired
behaviour is the following:
user=> (some #{:a} [:a :b :c])
:a
user=> (some #{:d} [:a :b :c])
nil
This will do the trick. With one little exception: in case boolean
false
and nil
are valid values in our collection we are in trouble.
user=> (some #{false} [:a false :b])
false
Doh! In this case we have to use #(= % false)
:
user=> (some #(= % false) [:a false :b])
true
Both versions are perfectly idiomatic Clojure.
Today we will close with the words of Chris Houser who puts things quite on the spot.
What is the drawback of the
(some #{:y} [:x :y :z])
idiom? Is it too verbose? Too slow? Too flexible? Too good a re-use of existing functionality? Too helpful in opening ones eyes to the possibilities of sets and higher order functions?
Published by Meikel Brandmeyer on .
I'm a long-time Clojure user and the developer of several open source projects mostly involving Clojure. I try to actively contribute to the Clojure community.
My most active projects are at the moment VimClojure, Clojuresque and ClojureCheck.
Copyright © 2009-2014 All Right Reserved. Meikel Brandmeyer