0

对于我正在工作的一些代码,我需要在宏中处理'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)

4

1 回答 1

0

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

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

(define var 'x)

(test 'x)
(test var)

test即使宏test进入(quote x)第一个而符号var进入第二个,这两种形式的数量也应该相同。在展开的var时候并不存在,因为执行可以展开所有的宏,然后再开始。

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

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

定义后,您将使用换行符获取'w(quote w)打印,然后它尝试存储的过程是:

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

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

于 2020-03-15T00:05:35.937 回答