2013-02-09 11 views

Odpowiedz

8

Wymień first z only (lub innego poetycko nazwie) funkcji o warunek wstępny, w którym chcesz dokonać twierdzenie:

(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

Tak. Ta odpowiedź. – dfreeman

+0

'(tylko [1 zero])' ilustruje błąd w tym rozwiązaniu. –

+1

@AlexBaranosky Chcesz wyjaśnić? '(następny [1 nil])' to ''(zero)' i '(zero?' (zero))' to 'false'. Tak więc '(tylko [1 zero])' zgłasza błąd potwierdzenia jako pożądany. –

1

Nie mogę od razu wymyślić ładnego, zwięzłego, idiomatycznego sposobu, aby to zrobić.

Opcja 1 polega na tym, że jej nie ma, ponieważ jest to sytuacja dziwna. Jeśli wiesz, że ma być dokładnie jeden element, dlaczego jest na liście?

Wariant 2 jest to, że jest tylko jedna, a ktoś przyjdzie i powie się za nie widząc to :)

Powiedział, że w sytuacji pewnie bym napisać coś takiego:

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

Możliwe, że po prostu możesz po prostu zrobić (count alist) i upewnić się, że miał dokładnie jeden przedmiot. Powyższy kod ma jednak dobrą właściwość, że nie wymusi oceny poza nagłówkiem listy, ale w zależności od twojego przypadku użycia, który może nie być problemem.

+1

Nie podoba mi się podejście "count", ponieważ nie jest to elastyczne rozwiązanie dla długich lub nieskończonych sekwencji. –

3

To będzie wysadzić w kolekcji niczym innym niż jednego elementu. Działa również na leniwych sekwensach.

(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 - To jest świetna odpowiedź, ponieważ oprócz unikania użycia 'count' może obsłużyć zarówno' (only nil) 'oraz' (only (sorted-map 1: a 2: b)) '. –

0

The Tupelo library ma tę funkcję zdefiniowaną jako rdzeń sanity-check, pozwalając na „otwierania” wartości skalarne od długości 1 wektorów/lista dokument zamierzony wynik. Definicja jest prostota sama:

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

można znaleźć podobną funkcję w SuchWow library i innych miejscach.

Powiązane problemy