【问题标题】:Standard way to handle quoted symbol in lisp macros in Scheme在 Scheme 中处理 lisp 宏中引用符号的标准方法
【发布时间】:2020-06-26 11:10:16
【问题描述】:

对于我正在工作的一些代码,我需要在宏中处理 'x。处理这些值的标准方法是什么?

我有这样的代码:

(define (quoted-symbol? x)
   (and (pair? x) (eq? (car x) 'quote) (symbol? (cadr x)) (null? (cddr x))))

(define-macro (test x)
   (if (quoted-symbol? x)
      `(begin
          (display ',(cadr x))
          (newline))))

(test 'hello) ;; 'hello will be expanded into list (quote hello)

这是应该如何处理的,还是只是在宏中你不使用带引号的符号?

注意:我问的不是卫生宏(我问的是真正的 lisp 宏),所以请不要回答卫生宏。

编辑

我的宏在 Guile 和 BiwaScheme 以及我自己的方案(如 JavaScript 中的 lisp)中都能正常工作。这是更好的例子:

(define-macro (test x)
   (if (quoted-symbol? x)
       `',(cadr x)))

(define (example arg)
  (list arg (test 'world)))

(example 'hello)

问题不是关于display,而是关于(cadr x)

EDIT2:你已经问过了,我的宏:

(define-macro (--> expr . code)
  "Helper macro that simplify calling methods on objects. It work with chaining

   usage: (--> ($ \"body\")
               (css \"color\" \"red\")
               (on \"click\" (lambda () (print \"click\"))))

          (--> document (querySelectorAll \"div\"))

          (--> (fetch \"https://jcubic.pl\") (text) (match /<title>([^<]+)<\/title>/) 1)

          (--> document (querySelectorAll \".cmd-prompt\") 0 \"innerText\")"
  (let ((obj (gensym)))
    `(let* ((,obj ,(if (and (symbol? expr) (not (null? (match /\./ (symbol->string expr)))))
                       `(.. ,expr)
                       `,expr)))
       ,@(map (lambda (code)
                (let ((name (gensym))
                      (value (gensym)))
                  `(let* ((,name ,(cond ((quoted-symbol? code) (symbol->string (cadr code)))
                                        ((pair? code) (symbol->string (car code)))
                                        (true code)))
                          (,value (. ,obj ,name)))
                     ,(if (and (pair? code) (not (quoted-symbol? code)))
                         `(set! ,obj (,value ,@(cdr code)))
                         `(set! ,obj ,value)))))
              code)
       ,obj)))

;; ---------------------------------------------------------------------------------------
(define (quoted-symbol? x)
   "(quoted-symbol? code)

   Helper function that test if value is quoted symbol. To be used in macros
   that pass literal code that is transformed by parser.

   usage:

      (define-macro (test x)
         (if (quoted-symbol? x)
             `',(cadr x)))

      (list 'hello (test 'world))"
   (and (pair? x) (eq? (car x) 'quote) (symbol? (cadr x)) (null? (cddr x))))

该宏在我的方案中使用,如 JavaScript 中的 lisp,如文档字符串建议:

(--> document (querySelectorAll ".class") 0 "innerText")

我要支持:

(--> document (querySelectorAll ".class") 0 'innerText)

代码可以在线测试:https://jcubic.github.io/lips/(您需要复制/粘贴代码,因为当前版本只允许方法调用)。

要获得扩展,您可以使用

(pprint (macroexpand (-->  document (querySelector "x"))))

如果它不起作用(不要扩展),则意味着宏被某种方式破坏了。

dot 是内置函数,用于获取对象的属性和.. 宏:

(define-macro (.. expr)
  "(.. foo.bar.baz)

   Macro that gets value from nested object where argument is comma separated symbol"
  (if (not (symbol? expr))
      expr
      (let ((parts (split "." (symbol->string expr))))
        (if (single parts)
            expr
            `(. ,(string->symbol (car parts)) ,@(cdr parts))))))

可用于获取嵌套属性,如 (.. document.body.innerHTML)

【问题讨论】:

  • 我认为你应该明确你想要达到的目标:你有什么目的特别对待引用的符号?如果宏的参数不是带引号的符号,扩展应该是什么?这一切都像一个 XY 问题。
  • 如果不是带引号的符号,您的上一版宏将返回 undefined。例如,(test var) 将失败,(test (quote var)) 扩展为 (quote var),然后通过方案将其评估为符号 var。身份宏的目的是什么?你能提出一个真正的问题吗?
  • @Sylwester 我已经按照你的要求用我的代码编辑了我的问题。
  • 我不知道足够多的 JS 来理解你想要做的事情的语义是什么,但几乎可以肯定的答案是不要在宏中这样做:让宏在语法上重写为-不太方便的函数调用(或一组函数调用),然后让函数处理字符串和符号之间的差异。

标签: scheme lisp lisp-macros


【解决方案1】:

方案没有“真正的 lisp 宏”。一些实现有类似的东西,但形式有不同的名称和用途。它们根本不便携。

处理'x 的标准方法是像在展开式中求值的表达式一样处理它。例如。

(define var 'x)

(test 'x)
(test var)

即使宏 test 在第一个中获得 (quote x) 而在第二个中获得符号 var,这两个 test 形式的数量也应该相同。在扩展时var 不存在,因为实现可以在开始之前扩展所有宏。

test 的实现将不起作用。例如。 display 可能会运行一两次,然后每次调用使用它的过程时它都会失败,因为扩展是未定义的值,它可能不适合评估。例如。

(define (example arg)
  (list arg (test 'w)))

当它被定义时,你会得到'w(quote w) 打印一个换行符,然后它尝试存储的过程是:

(define (example arg)
  (list arg #<undefined>))

请注意,构成未定义值的内容由实现选择,但我确信在许多实现中您无法评估#&lt;undefined&gt;

【讨论】:

  • 它工作正常,只是宏不返回任何内容,它只是打印参数,这就是它有#&lt;undefined&gt;的原因,它在Guile和biwaScheme中按预期工作。查看我的编辑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-23
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 2013-06-05
  • 1970-01-01
  • 2010-10-31
相关资源
最近更新 更多