2009-03-26 6 views
15

Sto dando un'occhiata all'eccellente tutorial Clojure here. In uno degli esempi che ha il codice Clojure secondo le seguenti linee:perché "(def vowel? (Set" aeiou "))" funziona?

(def vowel? (set "aeiou")) 

Questo rende vocale ritorno vero per le vocali e le consonanti false per:

(vowel? (first "abc")) ; => true 
(vowel? (first "cba")) ; => false 

Perché è questo? Suppongo che abbia qualcosa a che fare con il punto interrogativo dietro il nome della variabile. Impossibile trovare nulla subito nel tutorial ...


Edit ho appena realizzato vowel? non restituisce vero o falso, ma piuttosto l'elemento stesso o nullo. Vedi la mia risposta.

risposta

16

Questo è perfettamente analogo a come funzionano le mappe (gli oggetti più naturali in Clojure). Quando la mappa è chiamata come una funzione, funziona come una mappatura:

user=> (def ob {:foo "bar", :bar :baz, :qwerty 42}) 
#'user/ob 
user=> (ob :foo) 
"bar" 

Quindi ha senso che un insieme Clojure può essere definito come una funzione, e funziona come un test di appartenenza. A proposito, se si utilizzano parole chiave (quelle cose che iniziano con i due punti) come le chiavi di una mappatura, lavorano anche funzioni come simili, in modo da poter fare

user=> (:bar ob) 
:baz 

e perfino la stessa cosa con i set di parole chiave:

user=> (def vowel-keywords (set [:a :e :i :o :u])) 
#'user/vowel-keywords 
user=> (:a vowel-keywords) 
:a 
user=> (:b vowel-keywords) 
nil 

Ma, ancora una volta, quest'ultimo trucco funziona solo con le parole chiave, non altro che si potrebbe utilizzare come chiavi in ​​una mappatura o membri di un set.

7

Aha! Ho finito per scoprirlo da solo. In realtà non restituisce true o false, piuttosto restituisce la prima occorrenza nel set o zero se non si verifica.

E poiché è possibile utilizzare questo come condizione (nil viene gestito come falso e non nulla come vero), questo funziona come un piccolo trucco per verificare se una stringa contiene una lettera.

(vowel? (first "abc")) ; => "a" 
(vowel? (first "cba")) ; => nil 

(if (vowel? (first "abc")) 
     (println "yay") 
     (println "oops")) ; => "yay" 
+0

Mi sembra giusto. Il punto interrogativo indica che può essere usato come test. Vedrai spesso un punto esclamativo su funzioni con effetti collaterali. Non fanno parte della lingua, sono tradizioni libere (quindi conosci le funzioni sicure da quelle "pericolose"). – MBCook

+2

Per chiarire,? e ! sono solo caratteri come aeb, e puoi usarli per denominare i simboli (così come \, /, *, -, + ...). Ci sono delle tradizioni per nominare determinati simboli in Lisp, ma ci sono piccole differenze tra i dialetti. – Svante

+0

ah, grazie @svante! Pensavo che ci fosse qualcosa di magico nel "?" :) – Epaga