首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当值是语法规则时,定义和定义语法的区别是什么?

当值是语法规则时,定义和定义语法的区别是什么?
EN

Stack Overflow用户
提问于 2020-04-11 20:52:40
回答 1查看 245关注 0票数 0

我正在方案实现中实现卫生宏,我刚刚实现了syntax-rules,但我有以下代码:

代码语言:javascript
复制
(define odd?
  (syntax-rules ()
    ((_ x) (not (even? x)))))

这与此之间应该有什么区别:

代码语言:javascript
复制
(define-syntax odd?
  (syntax-rules ()
    ((_ x) (not (even? x)))))

据我所知,syntax-rules只是返回语法转换器,为什么不能仅仅使用define将其分配给符号呢?为什么我需要使用define-syntax?这句话还能做些什么?

首先也应该在计划中工作吗?还是只有第二个?

另外,letlet-syntaxletrecletrec-syntax的区别是什么?如果值是语法转换器,那么(define|let|letrec)-syntax应该只进行类型检查吗?

编辑

我有这个实现,仍然使用lisp宏:

代码语言:javascript
复制
;; -----------------------------------------------------------------------------
(define-macro (let-syntax vars . body)
  `(let ,vars
     ,@(map (lambda (rule)
              `(typecheck "let-syntax" ,(car rule) "syntax"))
            vars)
     ,@body))

;; -----------------------------------------------------------------------------
(define-macro (letrec-syntax vars . body)
  `(letrec ,vars
     ,@(map (lambda (rule)
              `(typecheck "letrec-syntax" ,(car rule) "syntax"))
            vars)
     ,@body))

;; -----------------------------------------------------------------------------
(define-macro (define-syntax name expr)
  (let ((expr-name (gensym)))
    `(define ,name
       (let ((,expr-name ,expr))
         (typecheck "define-syntax" ,expr-name "syntax")
         ,expr-name))))

这个代码是对的吗?

这个代码能起作用吗?

代码语言:javascript
复制
(let ((let (lambda (x) x)))
  (let-syntax ((odd? (syntax-rules ()
                        ((_ x) (not (even? x))))))
     (odd? 11)))
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-12 16:34:53

这个问题似乎意味着对宏有一些深层次的混淆。

让我们设想一种语言,其中syntax-rules返回一些语法转换器函数(我不确定这在RnRS方案中是正确的,我认为在Racket中是正确的),并且letlet-syntax是相同的。

因此,让我们编写这个函数:

代码语言:javascript
复制
(define (f v)
  (let ([g v])
    (g e (i 10)
       (if (= i 0)
           i
           (e (- i 1))))))

当然,我们可以转化为:

代码语言:javascript
复制
(define (f v n)
  (v e (i n)
     (if (<= i 0)
         i
         (e (- i 1)))))

此外,我还将告诉您,在环境中不存在对ei的绑定。

解释器与这个定义有什么关系?它能编译吗?它是否可以安全地推断i不可能有任何意义,因为它被用作一个函数,然后作为一个数字?它能安全地做任何事情吗?

答案是,不,它不能。直到它知道函数的参数是什么,它不能做任何事情。这意味着,每次调用f时,它都必须再次做出决定。特别是,v可能是:

代码语言:javascript
复制
(syntax-rules ()
  [(_ name (var init) form ...)
   (letrec ([name (λ (var)
                    form ...)])
     (name init))]))

在这个定义下,f的定义是有意义的。

事情变得更糟:更糟。这个怎么样?

代码语言:javascript
复制
(define (f v1 v2 n)
  (let ([v v1])
    (v e (i n)
       ...
       (set! v (if (eq? v v1) v2 v1))
       ...)))

这意味着,像这样的系统不知道它要解释的代码意味着什么,直到解释它的那一刻,甚至是在这一点之后,正如您从上面的第二个函数中可以看到的那样。

因此,Lisps没有做这种可怕的事情,而是做了一些明智的事情:他们将代码的评估过程分成几个阶段,每个阶段在概念上都发生在下一个阶段之前。

下面是一些想象中的Lisp的序列(这有点接近CL的功能,因为我大部分的知识都是这样的,但它并不打算代表任何特定的系统):

在这个阶段,代码可能在用户定义的code;

  • there's的帮助下,被用户和系统定义的代码(宏)重写为其他对象--这个阶段的结果是用函数和一些原始的特殊事物来表示的,传统上称为“特殊形式”,这是第3和第4阶段的进程所知道的;可能存在编译来自第二阶段的对象的阶段,该阶段可能涉及另一组用户定义的宏(编译器macros);

  • there是计算结果代码的阶段。

)。

对于每个代码单元,这些阶段按顺序进行,每个阶段在下一个阶段开始之前完成。

这意味着用户可以干预的每个阶段都需要自己的一组定义和绑定表单:例如,可以说“这个东西控制了第二阶段发生的事情”。

这就是define-syntaxlet-syntax &c所做的:他们说“这些绑定和定义控制着第二阶段发生的事情”。例如,您不能使用definelet来这样做,因为在第2阶段,这些操作还没有意义:它们只在第3阶段获得意义(可能本身是扩展到某些原始事物的宏)。在第2阶段,它们只是宏正在吞食和吐出的语法的一部分。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61163571

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档