2013-05-17 16 views
12

Pensavo di aver capito la destrutturazione, ma stavo leggendo un blog di clojure e questo mi ha confuso. Se avete una funzione scritta come:Perché è possibile passare coppie di valori chiave a una funzione che distrugge una mappa?

(defn f [& {:keys [foo bar]}] 
    (println foo " " bar)) 

Perché si può chiamare in questo modo:

(f :foo 1 :bar 2) 

Il mio primo pensiero è stato che la mia funzione doveva essere chiamato in questo modo:

(f {:foo 1 :bar 2}) 
IllegalArgumentException No value supplied for key: {:foo 1, :bar 2} clojure.lang.PersistentHashMap.createWithCheck (PersistentHashMap.java:89) 

Ma ovviamente questo non funziona. Penso che questo abbia qualcosa a che fare con il modo in cui funziona &. Ma ho sempre pensato che la cosa dopo è un vettore e quindi dovresti distruggere qualsiasi cosa dopo di essa come un vettore.

Qualcuno può spiegarmi come/perché questa definizione funziona come fa? Grazie

risposta

13

Il & e destrutturazione lavoro forma sequenziale:

  • Il & raccoglie argomenti dopo che in una collezione
  • La mappa forma destrutturazione poi prende la raccolta, effettua una mappa fuori di esso, se richiesto e associa i nomi alle chiavi elencate nel vettore.

Il vettore in forma mappa destrutturazione è solo sintassi utilizzata per costruire il desctructuring/vincolante e non implica nulla aobut il modulo di input

Il senza il & nel defn seconda forma funzionerà e la prima non lo farò.
Con il & il primo modulo funzionerà e il secondo no.

+0

"Il vettore in forma mappa destrutturazione è solo la sintassi" - anzi, un elenco funzionerà altrettanto bene qui. – Alex

7

È possibile vedere cosa sta succedendo sotto le coperte chiamando il numero destructure manualmente. Cominciamo con un esempio più semplice:.

user> (destructure ['{foo :foo} {:foo 42}]) 
[map__26147 {:foo 42} 
map__26147 (if (clojure.core/seq? map__26147) 
       (clojure.lang.PersistentHashMap/create 
       (clojure.core/seq map__26147)) 
       map__26147) 
foo (clojure.core/get map__26147 :foo)] 

Ciò corrisponde a (let [{foo :foo} {:foo 42}] ...) (come si può verificare con (macroexpand-1 '(let [{foo :foo} {:foo 42}] ...)) La seconda linea di uscita è il bit importante Una mappa forma vincolante può funzionare in due modi:. Se il valore essendo legato è un seq, il seq sarà 'versato' in una mappa hash (come se fosse (apply hash-map the-seq). Altrimenti, si presume che il valore sia associativo e usato direttamente.La funzione seq 'pouring' è stata aggiunta in this commit.

Proviamo:

user> (let [{foo :foo} {:foo 42}] foo) 
42 
user> (let [{foo :foo} (list :foo 42)] foo) 
42 
user> (let [{foo :foo} (apply hash-map (list :foo 42))] foo) 
42 

Nel primo caso, il valore non è un seq, quindi viene utilizzato direttamente. Nel secondo caso, una lista è un seq, quindi viene "versato" in una mappa hash prima di essere associato a {foo :foo}. Il terzo caso mostra che questo versamento è semanticamente equivalente a (apply hash-map the-seq).

Ora diamo un'occhiata a qualcosa come il tuo esempio:

user> (destructure '[[& {:keys [foo bar]}] args]) 
[vec__26204 args 
map__26205 (clojure.core/nthnext vec__26204 0) 
map__26205 (if (clojure.core/seq? map__26205) 
       (clojure.lang.PersistentHashMap/create 
       (clojure.core/seq map__26205)) 
       map__26205) 
bar (clojure.core/get map__26205 :bar) 
foo (clojure.core/get map__26205 :foo)] 

Il bit nthnext è dal & - in questo caso, perché non ci sono parametri fissi prima della &, abbiamo un (nthnext vec# 0), che ammonta a basta convertire args in un seq (se necessario). Quindi abbiamo la mappa destrutturante come sopra. Poiché il & garantisce che abbiamo un seq, il caso speciale seq per la destrutturazione delle mappe verrà sempre attivato e gli argomenti verranno sempre "riversati" in una mappa hash prima di essere associati al modulo della mappa.

Nel caso in cui il rapporto tra questo esempio e la vostra fn originale non è chiaro, prendere in considerazione:

user> (macroexpand-1 '(fn [& {:keys [foo bar]}])) 
(fn* ([& p__26214] (clojure.core/let [{:keys [foo bar]} p__26214]))) 
Problemi correlati