【问题标题】:trouble with lisp macro around and周围有 lisp 宏的麻烦和
【发布时间】:2019-09-08 05:59:13
【问题描述】:

所以我想编写一个 all 宏,它接受一个元素列表,如果它们都是非假的,则返回。我想把它作为一个宏来做,比如

(defmacro all (ls) 
  `(and ,@ls))

当我使用

进行测试时有效
(all (1 2 3))

但不是

(all '(1 2 3)) 

或任何其他列表。我不太确定为什么。我做错了什么?

【问题讨论】:

    标签: macros common-lisp


    【解决方案1】:

    1. ',引号是什么意思

    's-expression只是(QUOTE s-expression)的语法缩写,所以'(1 2 3)是二元素列表(QUOTE (1 2 3))的缩写

    2。如何评估宏

    宏是将一种形式(s 表达式)转换为另一种形式的函数,通常用于向语言添加新的句法结构。

    因此,宏的参数不会被计算。它们按字面意思理解并绑定到宏参数。

    因此,宏 all 在使用时将列表参数绑定到 ls 参数而不进行任何评估,并将列表转换为插入原子 and 作为第一个元素的新列表:

    (all (1 2 3))  =>  (AND 1 2 3)
    

    然后对生成的表单进行解释或编译以供后续评估。

    如果你写(all '(1 2 3),这相当于(all (QUOTE (1 2 3)),转换如下:

    (all '(1 2 3)) => (all (QUOTE (1 2 3)) => (AND QUOTE (1 2 3))
    

    这可能与您所期望的不同,并且会产生几个错误(变量QUOTE 未绑定,(1 2 3) 的汽车不是函数名称或 lambda 表达式)。

    3.调试宏

    如果您想查看宏是如何展开的,可以使用macroexpand-1 原语函数(参见manual):

    CL-USER> (macroexpand-1 '(all (1 2 3)))
    (AND 1 2 3)
    
    CL-USER> (macroexpand-1 '(all '(1 2 3)))
    (AND QUOTE (1 2 3))
    

    【讨论】:

    • 我认为 ,@x 应该评估 x 并拼接值。所以我不明白我应该如何将实际列表传递给这个宏,该宏将根据需要粘贴到 and 表达式中。
    • ,@x 采用与 x 关联的 s 表达式(即 (1 2 3)),并拼接列表。但是传递给宏的内容是从不评估的。您不能将运行时值传递给宏。例如,如果您执行(let ((x '(1 2 3))) (all x)),则会收到错误:“值 X 不是预期的类型 LIST。”。这是因为与ls 关联的s 表达式是符号X,而不是它的值。
    • 宏不能用于在运行时计算值,因为它应该使用函数。
    • 我真的不明白。是否声称不可能在宏内展开列表?我不相信会是这样。我相信必须有一种方法可以正确地做到这一点。在周围的情况下,甚至在调用宏之前就已经对列表进行了评估。当宏仍然不起作用时,我也尝试了一个 let。
    • 您应该区分文字列表(如 (1 2 3))和评估为列表的内容(例如变量)。您的 macro 接受文字列表,而通用 function 可以接受任何计算结果为列表的表达式。因此,您的宏只能使用必须修改的文字列表来调用,而不是使用任何评估为列表的表达式,如变量、函数或宏调用等。
    【解决方案2】:

    所以这行得通。

    (defmacro all (ls)
     `(reduce (lambda (a b) (and a b)) ,ls))
    

    虽然它不是那么简洁或让我满意。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-18
      • 2012-03-08
      • 2016-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多