2013-02-09 13 views

risposta

8

Sostituire first con una only (o altro poeticamente chiamato) funzione con una pre-condizione in cui si vuole fare la sua affermazione:

(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) 
+0

Sì. Questa risposta – dfreeman

+0

'(only [1 nil])' illustra un bug in questa soluzione. –

+1

@AlexBaranosky Cura di spiegare? '(next [1 nil])' is ''(nil)' e '(nil?' (nil))' è 'false'. Quindi, '(solo [1 nil])' genera un errore di asserzione come desiderato. –

1

Non riesco a pensare immediatamente a un modo sintetico e conciso per farlo.

L'opzione 1 è che non ce n'è uno, perché questa è una situazione un po 'strana. Se sai che ci dovrebbe essere esattamente un elemento, perché è in una lista in primo luogo?

opzione 2 è che ce n'è uno, e qualcuno arriverà e dirà off per non vederlo :)

Detto questo, nella vostra situazione avrei probabilmente scrivere qualcosa di simile:

(let [[item & rest] alist] 
    (if (nil? rest) 
    (throw (IllegalArgumentException. "Expected a single-element list")) 
    item)) 

Forse più semplicemente, si potrebbe anche solo fare (count alist) e assicurarsi che avesse esattamente un elemento. Il codice sopra, tuttavia, ha la bella proprietà che non imporrà la valutazione oltre il capo della lista, ma a seconda del caso d'uso che potrebbe non essere una preoccupazione.

+1

Non mi piace l'approccio 'count' perché non è una soluzione resiliente per sequenze lunghe o infinite. –

3

Questo farà saltare in aria su una collezione con qualcosa di diverso di un elemento. Funziona bene anche con i pigri seq.

(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"))))) 
+0

+1 - Questa è un'ottima risposta perché oltre a evitare l'uso di 'count', può gestire sia' (only nil) 'che' (only (sorted-map 1: a 2: b)) '. –

0

The Tupelo library ha questa funzione definita come sanity-check nucleo, permettendo di "scartare" valori scalari da lunghezza-1 vettori/liste e documentare il risultato previsto. La definizione è la semplicità stessa:

(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))) 

è possibile trovare una funzione simile nei SuchWow library e in altri luoghi.

Problemi correlati