2015-10-25 8 views
5

Desidero che una macro definisca funzioni che restituiscono il modulo in cui sono stati chiamati, ad es. (func 1 (a b)) restituisce (func 1 (a b)). Voglio anche consentire la verifica dell'input per queste funzioni per assicurarmi che non stia introducendo alcun bug. (Questi moduli verranno successivamente valutati, ma quel codice non è stato ancora scritto.)Definizione di una funzione in una macro: impossibile utilizzare il nome qualificato come parametro

Continuo a ricevere questo errore, però.

(defmacro defecho 
    "Echo function call after asserting a few things about the input" 
    ([f] `(defecho ~f nil nil)) 
    ([f assertions] `(defecho ~f assertions nil)) 
    ([f assertions assert-failed-message] 
    `(defn ~f [& body]    ; define a function 
     ~(when-not (nil? assertions) ; if given a function for input validation 
     `(assert (~assertions body) ; define the function to assert this as true 
        ~assert-failed-message)) ; with a given error message 
     (conj body (quote ~f)))))  ; return the (f [email protected]) list 

(defecho my-test 
    #(< 2 (count %)) 
    "Must be greater than zero") 
  1. Unhandled clojure.lang.Compiler$CompilerException 
    Error compiling: 
    /private/var/...228.clj:1:1 
    Can't use qualified name as parameter: my-test/body 
    
  2. Caused by java.lang.RuntimeException 
    Can't use qualified name as parameter: my-test/body 
    

risposta

4

Non è possibile utilizzare simboli qualificati come parametri di funzione. Si osservi che

`body 

viene valutato come current-namespace/body

In una sintassi-citazione, si può sempre unquote un preventivo non-sintattica per ottenere un simbolo non qualificato:

`~'body 

viene valutato come body. (Si noti che lo smascheramento qui serve a valutare la quotazione interna stessa).

Tuttavia, in questo caso è necessario generare un simbolo, perché se un utente utilizza il simbolo body all'interno di e. g il codice di assert-failed-message non si desidera che il suo binding di body sia ombreggiato con il proprio (osservare che il suo codice viene valutato quando viene effettivamente chiamata la funzione generata).

E 'pratica comune per generare simboli a tal fine, sia utilizzando gensym o un simbolo che termina con un hash, che la sintassi citazione si espanderà per una chiamata gensym ..

`body# 

restituisce il (non qualificata!) simbolo body__34343__auto__ dove il numero è diverso per ogni chiamata ed è garantito che sia diverso ogni volta.

Poiché si fa riferimento al corpo da due diverse citazioni di sintassi, ho scelto l'opzione gensym in combinazione con let in modo che venga generato un solo simbolo.

(defmacro defecho ; overloads stripped for brevity 
    [f assertions assert-failed-message] 
    (let [args-sym (gensym "body")] ; define a symbol for function arglist 
    `(defn ~f [& ~args-sym]    ; define a function 
     ~(when-not (nil? assertions)  ; if given a function for input validation 
      `(assert (apply ~assertions ~args-sym) ; define the function to assert this as true 
        ~assert-failed-message)) ; with a given error message 
     (conj ~args-sym (quote ~f))))) 
+0

È inoltre possibile utilizzare la sintassi 'body #' per auto gensym il nome. – drnewman

+0

@drnewman Poiché l'esempio usa 'body #' in due diversi contesti di citazione della sintassi, sarebbero generati simboli diversi. –

+0

Leon Grapenthin, hai ragione, grazie per la correzione – drnewman

0

È possibile rendere la vita un po 'più semplice utilizzando una funzione adeguata per il sollevamento di carichi pesanti e utilizzare la macro solo per lo zucchero di sintassi:

(defmacro defecho 
    "Echo function call after asserting a few things about the input" 
    ([f] `(defecho ~f nil nil)) 
    ([f assertions] `(defecho ~f assertions nil)) 
    ([f assertions assert-failed-message] 
    `(def ~f (echo-function (quote ~f) ~assertions ~assert-failed-message)))) 

(defn echo-function [f assertion assert-failed-message] 
    (fn [& body] 
    (when assertion 
     (assert (assertion body) 
       assert-failed-message)) 
    (conj body f))) 
Problemi correlati