Function definition in a macro: you cannot use a qualified name as a parameter

I want the macro to define functions that return the form they called, for example. (func 1 (ab)) returns (func 1 (ab)) . I also want to enable input validation for these functions to make sure that I did not enter any errors. (These forms will be evaluated later, but this code has not yet been written.)

I still get this error.

 (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 ~@body ) 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 
+5
source share
2 answers

You cannot use qualified characters as function parameters. notice, that

 `body 

takes the value current-namespace/body

In a syntax quote, you can always exclude a non-syntactic quote to get an unqualified character:

 `~'body 

body matters. (Note that the fuzzy rating here is for evaluating the innermost citation).

However, in this case, you should generate the character instead, because if the user uses the body character within e. g the code is assert-failed-message , you do not want its body binding to be obscured by yours (note that its code is evaluated when the generated function is called).

It is common practice to create characters for this purpose either using gensym or with a character ending with a hash, with the syntax quote extending to a call to gensym ..

 `body# 

evaluates the character (unskilled!) body__34343__auto__ , where the number is different for each call and it is guaranteed that it will be different every time.

Since you are referencing a body of two different syntax quotes, I selected the gensym option in combination with let so that only one character is generated.

 (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))))) 
+4
source

You can make your life a little easier by using the correct function for heavy lifting and use the macro only for syntactic sugar:

 (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))) 
0
source

Source: https://habr.com/ru/post/1234481/


All Articles