Macros Clojure,宏,可展开以执行带有代码的列表
好的,我有一个宏,它应该接受不同数量的参数,然后用try-and-catch执行它们。我假设如果参数列表Macros Clojure,宏,可展开以执行带有代码的列表,macros,clojure,Macros,Clojure,好的,我有一个宏,它应该接受不同数量的参数,然后用try-and-catch执行它们。我假设如果参数列表arg list大于2,那么列表中的第一个元素就是绑定,例如[a 0]。因此,arg list可能如下所示:([s(FileReader.(File.text.txt))](.s read)) 这就是我想到的: (defmacro safe [& arg-list] (list 'if (list '< (list 'count arg-list) '2) (list '
arg list
大于2,那么列表中的第一个元素就是绑定,例如[a 0]
。因此,arg list
可能如下所示:([s(FileReader.(File.text.txt))](.s read))
这就是我想到的:
(defmacro safe [& arg-list] (list 'if (list '< (list 'count arg-list) '2)
(list 'try (list 'eval arg-list) (list 'catch 'Exception 'e 'e))
(list 'do (list 'eval arg-list) (list 'try (list 'eval (list 'rest arg-list)) (list 'catch 'Exception 'e 'e)))))
我得到这个错误:
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn user/eval91 (NO_SOURCE_FILE:100)
我只与Clojure合作了四天,因此如果我的代码不好,请原谅。您不需要为此进行
eval
-宏扩展的结果已经评估过了。您需要的是在宏中使用语法引用最容易实现:
(defmacro safe [& args]
(if (< (count args) 2)
`(try ~@args (catch Exception e# e#))
`(let ~(first args)
(try ~@(rest args) (catch Exception e# e#)))))
(safe (+ 2 3)) => 5
(safe [x 3] (+ 2 x)) => 5
(safe (Integer/parseInt "a")) => #<NumberFormatException java.lang.NumberFormatException: For input string: "a">
通过将
(list'eval arg list)
更改为(list'eval(first arg list))
您不需要eval
来修复宏-宏扩展的结果已被评估。您需要的是在宏中使用语法引用来轻松完成:
(defmacro safe [& args]
(if (< (count args) 2)
`(try ~@args (catch Exception e# e#))
`(let ~(first args)
(try ~@(rest args) (catch Exception e# e#)))))
(safe (+ 2 3)) => 5
(safe [x 3] (+ 2 x)) => 5
(safe (Integer/parseInt "a")) => #<NumberFormatException java.lang.NumberFormatException: For input string: "a">
可以通过将
(list'eval arg list)
更改为(list'eval(first arg list))
来修复宏。。。首先,我建议您阅读clojure的宏语法。我会在这里提供一个有点拘谨,但我不打算深入
首先,这是你的宏
(defmacro safe [bindings? & forms]
(let [bindings (if (and (even? (count bindings?)) (vector? bindings?))
bindings? nil)
forms (if bindings forms (cons bindings? forms))
except `(catch Exception e# e#)]
(if bindings
`(let ~bindings (try ~@forms ~except))
`(try ~@forms ~except))))
现在让我们来看看
Clojure的(let)宏需要一个具有偶数个参数的向量,并支持一些真正有趣的行为,称为。在这个宏中,我假设任何有效的绑定参数首先是向量,其次是偶数长度。(let)的求值将执行相同的检查,但此宏必须执行此检查,因为第一个表单可能不是绑定,而是要求值的表单,并且在这种情况下应显示不同的行为
至于宏本身,我使用(let)来处理参数,即符号bindings
,用于指示绑定的存在以及在存在绑定向量时获取绑定向量的双重目的<代码>表单从参数中的初始绑定(clojure允许您这样做)重新定义为受绑定
影响的值,该绑定是您希望在包含错误的环境中执行的整个表单序列。除了符号之外,实际上并不需要它,它只是为了避免在每个扩展案例中重新启动(catch)表单的代码重复
我在这里使用的符号`(称为反引号或反勾号)与普通引号(')等效,只是clojure允许我在反引号形式和非引号形式中使用宏扩展语法。宏语法包含~(unquote)运算符和~@(insert(unquote))运算符。使用这三位表示法,我定义了两种需要的情况,一种是带有绑定形式的let,我在其中插入绑定形式和要尝试的形式,另一种是简单的try-only情况
可以消除条件反射以产生
(defmacro safe [bindings? & forms]
(let [bindings (if (and (even? (count bindings?)) (vector? bindings?))
bindings? [])
forms (if-not (empty? bindings)
forms (cons bindings? forms))
except `(catch Exception e# e#)]
`(let ~bindings (try ~@forms ~except))))
但是,当没有绑定形式时,就有多余的(let)。那么。。。首先,我建议您阅读clojure的宏语法。我会在这里提供一个有点拘谨,但我不打算深入 首先,这是你的宏
(defmacro safe [bindings? & forms]
(let [bindings (if (and (even? (count bindings?)) (vector? bindings?))
bindings? nil)
forms (if bindings forms (cons bindings? forms))
except `(catch Exception e# e#)]
(if bindings
`(let ~bindings (try ~@forms ~except))
`(try ~@forms ~except))))
现在让我们来看看
Clojure的(let)宏需要一个具有偶数个参数的向量,并支持一些真正有趣的行为,称为。在这个宏中,我假设任何有效的绑定参数首先是向量,其次是偶数长度。(let)的求值将执行相同的检查,但此宏必须执行此检查,因为第一个表单可能不是绑定,而是要求值的表单,并且在这种情况下应显示不同的行为
至于宏本身,我使用(let)来处理参数,即符号bindings
,用于指示绑定的存在以及在存在绑定向量时获取绑定向量的双重目的<代码>表单从参数中的初始绑定(clojure允许您这样做)重新定义为受绑定
影响的值,该绑定是您希望在包含错误的环境中执行的整个表单序列。除了符号之外,实际上并不需要它,它只是为了避免在每个扩展案例中重新启动(catch)表单的代码重复
我在这里使用的符号`(称为反引号或反勾号)与普通引号(')等效,只是clojure允许我在反引号形式和非引号形式中使用宏扩展语法。宏语法包含~(unquote)运算符和~@(insert(unquote))运算符。使用这三位表示法,我定义了两种需要的情况,一种是带有绑定形式的let,我在其中插入绑定形式和要尝试的形式,另一种是简单的try-only情况
可以消除条件反射以产生
(defmacro safe [bindings? & forms]
(let [bindings (if (and (even? (count bindings?)) (vector? bindings?))
bindings? [])
forms (if-not (empty? bindings)
forms (cons bindings? forms))
except `(catch Exception e# e#)]
`(let ~bindings (try ~@forms ~except))))
但是你有一个多余的(让)当没有绑定表单时。我将代码改为,但仍然收到相同的错误我不确定为什么需要处理arg list有多个表单的情况-try表单已经处理了多个表单。@Ceilingbat在该示例中,您不应该用语法引用全部内容-语法引用您想要的内容要发出的宏,但您的初始
if
应该在语法引号之外,因为您正在决定要发出的表单。如果你想传递绑定,你需要发出一个let
,而不是do
。哦,没错,if应该决定返回哪个表单。我从没想过那么远!我把我的代码改成了,但是我仍然收到了同样的错误我不确定为什么你需要处理arg list有多个表单的情况,try
表单已经处理了多个