2011-08-02 13 views
19

Citando Joy of Clojure, sezione 4.3.1--Perché utilizzando le parole chiave o simboli come funzioni di ricercare i valori dalle mappe funzionano?

perché le parole chiave sono auto-valutazione e di fornire controlli di uguaglianza veloci, sono quasi sempre utilizzati nel contesto delle chiavi della mappa. Una ragione altrettanto importante utilizzare parole chiave come chiavi mappa è che possono essere utilizzati come funzioni, prendendo una mappa come argomento, per eseguire ricerche di valore:

(def population {:zombies 2700, :humans 9}) 
(:zombies population) 
;=> 2700 
(println (/ (:zombies population) 
(:humans population)) 
"zombies per capita") 
; 300 zombies per capita 

Non è evidente per me che cosa sta succedendo Qui. In qualche modo (:zombies population) deve ottenere trasformato in (get population :zombies), giusto? Come funziona esattamente? La parola chiave valuta a sé stessa, non a una funzione. Ha il lettore guardare fuori per i casi in cui la prima cosa in una lista è una parola chiave, e aggiungere ottenere e spostare la parola chiave alla fine della lista?

risposta

22

Citation da official documentation:

Parole implementare IFN per invoke() di un argomento (una mappa), con un secondo argomento opzionale (un valore di default). Per esempio (: MyKey my-hash-map: nessuno) lo stesso significato (ottenere il mio-hash-map: mykey: nessuno). Vedi get.

E Clojure può chiamare parola chiave come funzione, poiché implementa la stessa interfaccia della funzione. Lo stesso è per i simboli ...

+0

È interessante notare che il primo argomento non deve essere una mappa: (: foo: bar: baz) i rendimenti: baz – KingCode

+0

@KingCode Se non si tratta di una 'ILookup', un java' Mappa ', o' IPersistentSet', quindi 'getFrom' in' RT' restituisce semplicemente 'null', nel qual caso il metodo' invoke' in 'Keyword' restituisce semplicemente il valore' notFound', o ': baz' nell'esempio . – Josh

16

Parole sono funzioni, in ogni modo. Non v'è nessun lettore magia coinvolti, come si vedrà se si tenta (let [m {:humans 100}, k :humans] (k m)). Spero tu sia d'accordo che il lettore non può in alcun modo trasformare questo in un get (il compilatore potrebbe, ma puoi fingere di aver fatto il valore di a dipendere da un'espressione if che il compilatore non può prevedere, come input dell'utente).

Poiché i tipi di dati principali di Clojure sono interfacce e gli oggetti Java possono implementare molte interfacce, un dato può avere più tipi. È una parola chiave? Sì. È una funzione? Anche sì:

user> (keyword? :k) 
true 
user> (ifn? :k) 
true 
user> (.invoke :k {:k 1}) 
1 
Problemi correlati