I know at some point in my code that a list has only one element, so I get it with
(first alist)
But I would also like the code to break if there were several items in the list to warn me of an erroneous state. What is the idiomatic way to achieve this in Clojure?
Replace firstwith a function only(or another poetically named one) with the precondition in which you want to make your statement:
first
only
(defn only [x] {:pre [(nil? (next x))]} (first x)) (only [1]) => 1 (only [1 2]) => AssertionError Assert failed: (nil? (next x)) user/only (NO_SOURCE_FILE:1)
This will lead to an explosion in the collection with something other than one element. Works well on lazy sections.
(defn only "Gives the sole element of a sequence" [coll] (if (seq (rest coll)) (throw (RuntimeException. "should have precisely one item, but had at least 2")) (if (seq coll) (first coll) (throw (RuntimeException. "should have precisely one item, but had 0")))))
, .
1 , , . , , ?
2 , , - , :)
, , , - :
(let [[item & rest] alist] (if (nil? rest) (throw (IllegalArgumentException. "Expected a single-element list")) item))
, , (count alist) , . , , , .
(count alist)
Tupelo , , "" -1/ . - :
(defn only "(only coll) Ensures that a sequence is of length=1, and returns the only value present. Throws an exception if the length of the sequence is not one. Note that, for a length-1 sequence S, (first S), (last S) and (only S) are equivalent." [coll] (let [coll-seq (seq coll) num-items (count coll-seq)] (when-not (= 1 num-items) (throw (IllegalArgumentException. (str "only: num-items must=1; num-items=" num-items)))) (clojure.core/first coll-seq)))
SuchWow library .