Il problema qui è sottile e possibilmente difficile da trovare senza prima capire un po 'sulle macro.
Le macro manipolano la sintassi nello stesso modo in cui le funzioni gestiscono i valori. In effetti, le macro sono solo funzioni con un hook che le fa valutare al momento della compilazione. Sono passati i dati letterali che vedi nel codice sorgente e sono valutati dall'alto verso il basso. Facciamo una funzione e una macro che hanno lo stesso corpo in modo da poter vedere la differenza:
(defmacro print-args-m [& args]
(print "Your args:")
(prn args))
(defn print-args-f [& args]
(print "Your args:")
(prn args))
(print-args-m (+ 1 2) (str "hello" " sir!"))
; Your args: ((+ 1 2) (str "hello" " sir!"))
(print-args-f (+ 1 2) (str "hello" " sir!"))
; Your args: (3 "hello sir!")
macro vengono sostituite dal loro valore di ritorno. È possibile controllare questo processo con macroexpand
(defmacro defmap [sym & args]
`(def ~sym (hash-map [email protected]))) ; I won't explain these crazy symbols here.
; There are plenty of good tutorials around
(macroexpand
'(defmap people
"Steve" {:age 53, :gender :male}
"Agnes" {:age 7, :gender :female}))
; (def people
; (clojure.core/hash-map
; "Steve" {:age 53, :gender :male}
; "Agnes" {:age 7, :gender :female}))
A questo punto, forse dovrei spiegare che '
provoca il seguente modulo per essere quote
d. Ciò significa che il compilatore leggerà il modulo, ma non lo eseguirà o tenterà di risolvere i simboli e così via. Ad esempio, 'conj
valuta un simbolo, mentre conj
valuta una funzione. (eval 'conj)
equivale a (eval (quote conj))
equivale a conj
.
Con questo in mente, sappi che non puoi risolvere un simbolo come uno spazio dei nomi finché non è stato magicamente importato nel tuo spazio dei nomi in qualche modo. Questo è ciò che fa la funzione require
. Prende i simboli e trova gli spazi dei nomi a cui corrispondono, rendendoli disponibili nello spazio dei nomi corrente.
Vediamo cosa la macro ns
si espande a:
(macroexpand
'(ns sample.core
(:require clojure.set clojure.string)))
; (do
; (clojure.core/in-ns 'sample.core)
; (clojure.core/with-loading-context
; (clojure.core/refer 'clojure.core)
; (clojure.core/require 'clojure.set 'clojure.string)))
Vedi come citato i simboli clojure.set
e clojure.string
per noi? Quanto conveniente! Ma qual è il problema quando si utilizza require
anziché :require
?
(macroexpand
'(ns sample.core
(require clojure.set clojure.string)))
; (do
; (clojure.core/in-ns 'sample.core)
; (clojure.core/with-loading-context
; (clojure.core/refer 'clojure.core)
; (clojure.core/require 'clojure.set 'clojure.string)))
Sembra che chi ha scritto la macro ns
stato abbastanza gentile da farci fare entrambe le cose, dal momento che questo risultato è esattamente lo stesso di prima. Neato!
edit: tvachon ha ragione su solo con :require
dal momento che è l'unica forma
ufficialmente supportato Ma qual è il problema con le staffe?
(macroexpand
'(ns sample.core
(:require [clojure.set]
[clojure.string])))
; (do
; (clojure.core/in-ns 'sample.core)
; (clojure.core/with-loading-context
; (clojure.core/refer 'clojure.core)
; (clojure.core/require '[clojure.set] '[clojure.string])))
scopre che vengono citati anche, proprio come faremmo se stessimo scrivendo chiamate standalone per require
.
Si scopre anche che ns
non interessa se gli forniamo elenchi (parenti) o vettori (parentesi) con cui lavorare. Vede solo gli argomenti come sequenze di cose. Ad esempio, questo funziona:
(ns sample.core
[:gen-class]
[:require [clojure.set]
[clojure.string]])
require
, come ha sottolineato amalloy nei commenti, ha una semantica diverse per i vettori e le liste, in modo da non mescolare quelle up!
Infine, perché il seguente lavoro non funziona?
(ns sample.core
(:require 'clojure.string 'clojure.test))
Ebbene, dal momento che ns
fa il nostro citando per noi, questi simboli ottenere citato due volte, che è semanticamente differente da essere citato solo una volta ed è anche pura pazzia.
conj ; => #<core$conj [email protected]>
'conj ; => conj
''conj ; => (quote conj)
'''conj ; => (quote (quote conj))
Spero che questo aiuta, e vi consiglio caldamente imparare a scrivere le macro. Sono super divertenti.
possibile duplicato di [Perché il modulo ns richiede un comportamento diverso dalla funzione di richiesta] (http://stackoverflow.com/questions/3719929/why-does-require-in-the-ns-form-behave- different-from-the-require-function) –
Hm, in realtà non chiede le [] e le differenze tra il codice repl e clj. –