【问题标题】:Can one apply a macro to an argument list?可以将宏应用于参数列表吗?
【发布时间】:2019-12-23 10:40:10
【问题描述】:

我的目标是能够将宏应用到参数列表,就像 apply 原始过程将过程应用到参数列表一样。

该列表在应用宏时已经被评估,没有办法解决这个问题,这很好;我想知道是否有任何方法可以以编程方式将列表“拼接”到宏应用程序中(与unquote-splicing 具有相同的意义)。困难在于不能将宏标识符作为参数传递。

一个用例是

(apply and list)

相当于

(not (memq #f list))

查看列表中是否有#f。 最好是符合 R7RS 标准。

一种 hacky 方式是(建议 on reddit

(eval (cons 'and list))

但这不符合 R7RS,因为 eval 必须采用环境参数,而且在我看来,标准并没有指定如何在调用 eval 时有效地获取环境。

另一个半解决方案如下,仅当列表直接作为带括号的值序列给出时才有效:

(syntax-rules ()
  ((_ identifier (val ...))
   (identifier val ...)))

【问题讨论】:

    标签: list macros scheme eval apply


    【解决方案1】:

    没有 eval 就无法做到这一点。您需要实现 AND 的过程版本。

    不可能的原因是因为宏观扩展是一个阶段,而评估是一个后期阶段。该列表是只存在于后期阶段的动态数据,因此宏不能使用它。

    【讨论】:

    • 即使使用eval 也没有办法做到这一点吗?如果可以在程序执行的给定时刻封装有效的环境并将其传递给eval,那么我给出的“hacky”示例将是令人满意的。
    • 正如您所证明的,它可以用 eval 完成。我会在我的答案中添加一个注释。谢谢!
    【解决方案2】:

    我将此作为我对自己的问题找到的部分答案发布,如果没有新消息弹出,我会在几天内接受。

    以下方法有效,但前提是要应用的宏包含在库中。

    (import (scheme base)
            (scheme eval)
            (scheme write))
    
    (define (apply-macro mac args . libs)
      (eval (cons mac args)
            (apply environment libs)))
    
    (define list '(#f #t #t #t))
    
    (display (apply-macro 'and      list  '(scheme base)))    ; => #f
    (display (apply-macro 'and (cdr list) '(scheme base)))    ; => #t
    

    【讨论】:

      【解决方案3】:

      你不能那样做;宏适用于语法,将代码片段转换为其他代码片段,而不是值。

      即使你能做到,它也不等同于应用and,因为list 的所有元素都会被评估。

      例如,如果你定义了非终止过程,

      (define (forever) (forever))
      

      那么(and #f (forever))#f,但(apply and (list #f (forever))) 不会终止。

      【讨论】:

      • 问题更多是关于如何解压列表,而不是关于and 本身,我作为一个(可能被过分强调)的例子。查看我的编辑。
      • @Olius 这个答案也更多地是关于为什么你不能这样做,而不是关于 and 特别是 - 没有你可以“解包”的列表。您关于“在应用宏时已经对列表进行评估”的说法根本不正确;在评估之前应用宏,这是没有办法的。
      猜你喜欢
      • 2014-05-27
      • 2013-03-28
      • 1970-01-01
      • 2013-08-09
      • 1970-01-01
      • 2021-06-12
      • 1970-01-01
      • 2020-01-12
      • 1970-01-01
      相关资源
      最近更新 更多