首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >由关键字触发的方案宏,该关键字不是列表的头。

由关键字触发的方案宏,该关键字不是列表的头。
EN

Stack Overflow用户
提问于 2012-05-28 23:33:14
回答 2查看 396关注 0票数 7

假设我想对s-表达式中的第一项以外的其他内容触发Scheme宏。例如,假设我想用infix样式的define替换:=,这样:

代码语言:javascript
复制
(a := 5) -> (define a 5)
((square x) := (* x x)) -> (define (square x) (* x x))

实际的转变似乎相当简单。诀窍将是获得方案,以找到:=表达式和宏展开它们。我考虑过用标准宏(可能是:(with-infix-define expr1 expr2 ...) )包围使用infix语法的代码,并让标准宏遍历其正文中的表达式并执行任何必要的转换。我知道,如果采用这种方法,我将不得不小心地避免转换实际上应该是数据的列表,例如引号列表,以及某些准引用列表的部分。我设想的一个例子是:

代码语言:javascript
复制
(with-infix-define
   ((make-adder n) := (lambda (m) (+ n m)))

   ((foo) :=
       (add-3 := (make-adder 3))
       (add-6 := (make-adder 6))
       (let ((a 5) (b 6))
           (+ (add-3 a) (add-6 b))))

   (display (foo))
   (display '(This := should not be transformed))

所以,我的问题有两方面:

  1. ,如果我走with-infix-define路线,除了报价和准报价之外,我还需要注意其他绊脚石吗?
  2. --我觉得我有点像在重新发明方向盘。这种类型的代码遍历看起来就像标准宏展开系统必须做的事情--唯一的区别是,在决定是否进行任何代码转换时,它们只查看列表中的第一项。有什么方法可以让我回到现有的系统上吗?
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-05-29 05:27:37

  1. 在继续这样做之前,最好仔细考虑一下-- IME --您通常会发现,您真正想要的是将:=作为infix语法进行读者级的处理。当然,这也意味着它在引号等方面也有问题,所以现在看来很糟糕,但我的经验是,你最终会意识到,最好是做一些consistently.
  2. For完整性的事情,我会提到,在would中,有一种类似于infix的表达式的读语法黑客:(x . define . 1)被读为(define x 1)。(正如上面所述,everywhere.)
  3. Otherwise,,您的包装宏的想法几乎是您唯一能做的事情。但是,这并不意味着完全没有希望,您可能对实现的扩展程序有一个钩子,它允许您执行这样的任务--例如,Racket有一个名为#%module-begin的特殊宏,它包装了一个完整的模块体,而#%top-interaction则封装了REPL上的分层表达式。(这两种方法都是在这两种上下文中隐式添加的。)下面是一个示例(为了简单起见,我使用了Racket的define-syntax-rule ):

#lang racket/base (提供(除了-out(所有的球拍/基)#%模块-开始#%的顶部交互)(重命名出我的模块-开始#%的模块-开始))(定义-语法嵌入-def(语法-规则(:= begin) ) (_ (begin E.)(infix-def E) .) (_ E) (定义-语法规则(my-模块-begin E.)(#%模块-begin (infix-def E) .))(定义-语法-规则(我的-顶部-交互)。E) (#%顶极交互作用)。(infix-def E))

如果我将其放入一个名为my-lang.rkt的文件中,现在可以如下所示使用它:

#lang s-exp "my-lang.rkt“(x := 10) ((fib n) := (完成?:= (<= n 1)(如果完成?N (+ (fib (- n1)) (fib (- n2) (fib X)

  • 是的,您需要处理很多事情。上面的两个例子是处理begin表达式和处理函数体。这显然是一个非常片面的列表--你也会想要一些lambdalet,等等。但是这仍然比一些盲目的按摩要好,因为这是不实际的,因为你不能事先知道一些随机的代码是如何结束的。作为一个简单的例子,请考虑下面这个简单的宏:

(定义-语法-规则(E轨道)(开始(eprintf )评估:~s\n“' E) ) (x := 1)

  • 这是一个正确的解决方案,你需要一些方法预展开代码,这样你就可以扫描它并处理你的:=中已知的几个核心形式--所有这些都是重复宏扩展器所做的工作,但是既然你正在改变扩展的方式,就没有办法绕过它了。(要了解为什么这是一个根本性的变化,请考虑一些类似于(if := 1)的东西-这是一个条件表达式还是一个定义?你如何决定哪个优先?)因此,对于具有“可爱语法”的语言,一种更流行的方法是将代码读入普通的S-表达式,然后让实际的语言实现使用简单的函数和宏.

票数 12
EN

Stack Overflow用户

发布于 2012-05-29 09:46:56

重新定义define有点复杂。见伊莱的精辟解释。

另一方面,如果您满足于:=使用set!,那么事情就会简单一些。

下面是一个小例子:

代码语言:javascript
复制
#lang racket

(module assignment racket
  (provide (rename-out [app #%app]))

  (define-syntax (app stx)
    (syntax-case stx (:=)
      [(_ id := expr)
       (identifier? #'id)
       (syntax/loc stx (set! id expr))]      
      [(_ . more) 
       (syntax/loc stx (#%app . more))])))

(require 'assignment)

(define x 41)
(x := (+ x 1))
(displayln x)

为了将该示例保留为单个文件,我使用了子模块(在Racket的预发布版本中可获得)。

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

https://stackoverflow.com/questions/10791481

复制
相关文章

相似问题

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