Clojure中,宏扩展到执行的代码列表(Clojure, macro that expands t

2019-10-17 14:24发布

好了,所以我有这个宏,应该采取不同数量的参数,然后用try和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 '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)))))

我一直在努力得到这个现在像两连胜天工作,但它永远不会奏效。 当我尝试这个宏与这个例子:

(safe (+ 2 3))

我得到这个错误:

ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn  user/eval91 (NO_SOURCE_FILE:100)

我只一直在使用Clojure四天所以原谅我,如果我的代码是坏的。

Answer 1:

嗯......一开始我建议你在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)处理参数,符号bindings服务指示绑定的存在,以及考虑绑定向量如果存在的双重目的。 forms从其初始重新定义在参数结合(Clojure的让你做到这一点),其是由所影响的值bindings您希望在一个包含差错的环境中执行是整个形式序列。 在except符号确实不叫了,它只是逃避重申的是(捕)的形式在每个扩大案件的重复代码。

我用符号`(被称为反引号或反引号)相当于这里正常引号(')不同的是Clojure的允许我使用反引号形式,而不是引用表单中的宏扩展语法。 宏语法包含〜(引文结束)运算符和〜@(插入(引文结束))uperator。 使用符号的这三位我定义了两种期望的情况下,与在那里我插入结合形式的结合形式和形式的让利受审并尝试简单的唯一案例。

有条件可以消除生产

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

但你有多余的(让)时,有没有结合的形式。



Answer 2:

你不需要eval宏扩展的结果已经eval'ed -此。 你想要的是最容易使用的语法,引用您的宏中实现什么:

(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">

之所以你看到的例外是, arg-list在你的榜样将是形式的列表,而你的情况有一个项目是列表'(+ 2 5) 当你EVAL其第一个项目是一个列表,然后内部形式eval'ed先外形式eval'ed列表:

(eval '(+ 2 3)) => 5
(eval '((+ 2 3))) => (eval '(5)) => exception, because 5 is not a function.

您的宏可能通过改变固定(list 'eval arg-list)(list 'eval (first arg-list))



文章来源: Clojure, macro that expands to execute a list with code