Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 通过宏传递已分解的参数_Clojure_Macros_Destructuring - Fatal编程技术网

Clojure 通过宏传递已分解的参数

Clojure 通过宏传递已分解的参数,clojure,macros,destructuring,Clojure,Macros,Destructuring,我在编写使用析构函数参数的宏时遇到了一些问题。以下是一个例子: (defmacro defny [n args & forms] `(defn ~n ~args ~@forms)) (defmacro defnz [n f args & forms] `(defn ~n ~args (do (~f ~@args) ~@forms))) (defny y [{:keys [value] :as args}] (print

我在编写使用析构函数参数的宏时遇到了一些问题。以下是一个例子:

(defmacro defny
  [n args & forms]
  `(defn ~n ~args ~@forms))

(defmacro defnz
  [n f args & forms]
  `(defn ~n ~args
    (do 
      (~f ~@args)
      ~@forms)))

(defny y
  [{:keys [value] :as args}]
  (println "Y ARGS" args)
  (println "Y VALUE" value))

(defnz z y
  [{:keys [value] :as args}]
  (println "Z ARGS" args)
  (println "Z VALUE" value))
在这里,我有两个宏,defny,它只调用defn,defnz,它执行相同的操作,但另外接受另一个函数,该函数在使用defnz的args调用函数体之前调用

当我调用z时,我希望看到值和参数都打印出来,但是我得到:

(z {:value 1})
Y ARGS {:keys [1], :as {:value 1}}
Y VALUE nil
Z ARGS {:value 1}
Z VALUE 1
=> nil

我可以理解为什么会发生这种情况,分解的args{:keys[1]:as{:value 1}}正在传递给y,但我不确定如何修复宏defnz,以便正确传递分解的args。

您可以很容易地看到宏扩展的错误:

(defnz z y
  [{:keys [value] :as args}]
  (println "Z ARGS" args)
  (println "Z VALUE" value))
扩展到:

(defn z [{:keys [value], :as args}]
  (do
    (y [{:keys [value], :as args}])
    (println "Z ARGS" args)
    (println "Z VALUE" value)))
您是正确的:您将整个args表单传递给y,但是您需要将该行扩展为
(y args)
,其中
args
只是一个普通符号。要在宏中执行此操作(将符号转换为非命名空间限定的符号),应使用“quote unquote”技巧:

现在,扩展将是正确的:

(defn z [{:keys [value], :as args}]
  (do (y args) (println "Z ARGS" args) (println "Z VALUE" value)))
但这是一个相当糟糕的主意,因为您不知道将传递给
defnz
的allargs名称是什么,比如{:keys[value]:as all}将失败(因为
defnz
期望它是
args
。您可以通过在
defnz
中动态检索allargs名称来修复它:

(defmacro defnz
  [n f [a :as args] & forms]
  (let [a (if (:as a) a (assoc a :as 'everything))]
    `(defn ~n ~[a]
       (do 
         (~f ~(:as a))
         ~@forms))))
因此,现在它将扩展到以下方面:

(defnz z y
  [{:keys [value] :as args}]
  (println "Z ARGS" args)
  (println "Z VALUE" value))

;;(defn z [{:keys [value], :as args}]
;;  (do (y args) (println "Z ARGS" args) (println "Z VALUE" value)))


(defnz z y
  [{:keys [value] :as all-args}]
  (println "Z ARGS" all-args)
  (println "Z VALUE" value))

;;(defn z [{:keys [value], :as all-args}]
;;  (do
;;    (y all-args)
;;    (println "Z ARGS" all-args)
;;    (println "Z VALUE" value)))

(defnz z y
  [{:keys [value]}]
  (println "Z ARGS" everything)
  (println "Z VALUE" value))

;;(defn z [{:keys [value], :as everything}]
;;  (do
;;    (y everything)
;;    (println "Z ARGS" everything)
;;    (println "Z VALUE" value)))

您很容易看到宏扩展的错误:

(defnz z y
  [{:keys [value] :as args}]
  (println "Z ARGS" args)
  (println "Z VALUE" value))
扩展到:

(defn z [{:keys [value], :as args}]
  (do
    (y [{:keys [value], :as args}])
    (println "Z ARGS" args)
    (println "Z VALUE" value)))
您是正确的:您将整个args表单传递给y,但您需要的是将该行扩展为
(y args)
,其中
args
只是一个普通符号。要在宏中执行此操作(这将使符号变为非命名空间限定的符号),您应该使用“quote unquote”技巧:

现在,扩展将是正确的:

(defn z [{:keys [value], :as args}]
  (do (y args) (println "Z ARGS" args) (println "Z VALUE" value)))
但这是一个相当糟糕的主意,因为您不知道将传递给
defnz
的allargs名称是什么,比如{:keys[value]:as all}将失败(因为
defnz
期望它是
args
。您可以通过在
defnz
中动态检索allargs名称来修复它:

(defmacro defnz
  [n f [a :as args] & forms]
  (let [a (if (:as a) a (assoc a :as 'everything))]
    `(defn ~n ~[a]
       (do 
         (~f ~(:as a))
         ~@forms))))
因此,现在它将扩展到以下方面:

(defnz z y
  [{:keys [value] :as args}]
  (println "Z ARGS" args)
  (println "Z VALUE" value))

;;(defn z [{:keys [value], :as args}]
;;  (do (y args) (println "Z ARGS" args) (println "Z VALUE" value)))


(defnz z y
  [{:keys [value] :as all-args}]
  (println "Z ARGS" all-args)
  (println "Z VALUE" value))

;;(defn z [{:keys [value], :as all-args}]
;;  (do
;;    (y all-args)
;;    (println "Z ARGS" all-args)
;;    (println "Z VALUE" value)))

(defnz z y
  [{:keys [value]}]
  (println "Z ARGS" everything)
  (println "Z VALUE" value))

;;(defn z [{:keys [value], :as everything}]
;;  (do
;;    (y everything)
;;    (println "Z ARGS" everything)
;;    (println "Z VALUE" value)))

尝试
macroexpand
macroexpand-1
查看宏生成的代码。尝试
macroexpand
macroexpand-1
查看宏生成的代码。