Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/azure/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Macros 由非列表标题的关键字触发的方案宏_Macros_Lisp_Scheme - Fatal编程技术网

Macros 由非列表标题的关键字触发的方案宏

Macros 由非列表标题的关键字触发的方案宏,macros,lisp,scheme,Macros,Lisp,Scheme,假设我想在s表达式中的第一项之外的其他项上触发一个Scheme宏。例如,假设我想用中缀样式替换定义:=,以便: (a := 5) -> (define a 5) ((square x) := (* x x)) -> (define (square x) (* x x)) 实际的转变似乎相当简单。诀窍是让Scheme找到:=表达式并进行宏扩展。我曾经考虑过围绕使用中缀语法和标准宏的大部分代码,可能是:(使用中缀define expr1 expr2…,让标准宏遍历其主体中的表达式并执行

假设我想在s表达式中的第一项之外的其他项上触发一个Scheme宏。例如,假设我想用中缀样式替换
定义
:=
,以便:

(a := 5) -> (define a 5)
((square x) := (* x x)) -> (define (square x) (* x x))
实际的转变似乎相当简单。诀窍是让Scheme找到
:=
表达式并进行宏扩展。我曾经考虑过围绕使用中缀语法和标准宏的大部分代码,可能是:
(使用中缀define expr1 expr2…
,让标准宏遍历其主体中的表达式并执行任何必要的转换。我知道如果我采用这种方法,我必须小心避免转换实际上应该是数据的列表,例如引用的列表和准引用列表的某些部分。我设想的一个例子:

(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))
因此,我的问题有两个:

  • 如果我使用中缀定义的
    路线,除了quote和QUISQUOTE之外,我是否需要注意任何绊脚石
  • 我觉得我有点像是在重新发明轮子。这种类型的代码漫游似乎正是标准宏扩展系统必须做的事情——唯一的区别是,它们在决定是否进行任何代码转换时只查看列表中的第一项。有没有什么方法可以让我只依靠现有的系统
  • 在继续此操作之前,最好仔细考虑一下——通常您会发现真正需要的是读取器级的中缀语法处理
    :=
    。这当然意味着它在引文等中也是中缀,所以现在看起来很糟糕,但我的经验是,你最终会意识到,始终如一地做事更好

  • 为了完整起见,我要提到在Racket中有一个类似中缀表达式的读取语法黑客:
    (x.define.1)
    被读取为
    (define x 1)
    。(如上所述,它在任何地方都有效。)

  • 否则,包装宏的想法几乎是唯一可以做的事情。但这并不是说它完全没有希望,您可能在实现的扩展器中有一个钩子,可以让您执行这些操作——例如,Racket有一个特殊的宏,名为包装完整的模块体,并包装REPL上的顶级表达式。(这两个都是在这两个上下文中隐式添加的。)下面是一个示例(为了简单起见,我使用Racket的):

    如果我把它放在一个名为
    my-lang.rkt
    的文件中,我现在可以按如下方式使用它:

    #lang s-exp "my-lang.rkt"
    (x := 10)
    ((fib n) :=
     (done? := (<= n 1))
     (if done? n (+ (fib (- n 1)) (fib (- n 2)))))
    (fib x)
    
  • 这样做的结果是,对于一个合适的解决方案,您需要某种方法来预扩展代码,这样您就可以扫描它,并处理实现中少数已知的核心形式

  • 是的,所有这些都是重复宏扩展器所做的工作,但由于您正在改变扩展器的工作方式,因此无法解决这一问题。(看看为什么它是一个根本性的改变,考虑一些类似于<代码>(IF:=1)< /代码>这是一个条件表达式还是一个定义?你如何决定哪个优先?因为这个原因,对于这样一个“可爱的语法”的语言,一个更流行的方法是读代码并把它解析成简单的S表达式,然后让实际的语言实现使用普通函数和宏


  • 重新定义
    定义
    有点复杂。见@Eli的精彩解释

    另一方面,如果您满足于
    :=
    使用
    设置事情稍微简单一点

    下面是一个小例子:

    #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的预发布版本中提供)。

    Scheme是否有code walker软件包?似乎您所需要做的就是将代码包装在with宏中,遍历该代码并将:=与前面的s-exp交换,然后定义一个符号宏,使:=等效于define。不过,我不确定引用的s-EXP。谢谢soegaard;但是为什么我不能将您的解决方案也应用到
    定义中呢?如果每个表达式都隐式地包装在#%app中,那不是很有效吗?简而言之:定义不是表达式。定义和表达式可以出现在不同的位置。考虑一个Lead绑定的右边,因此,不是每个定义类的表单都必须用Ay%%App来包装吗?或者是一些定义不合适的表单用#%app包装(我假设是在你的let示例中)?不,只有应用程序用#%app包装。有关定义与表达式的法律上下文,请参见。有关#%app的显示方式的信息,请参阅。嗯。。。我可以看出我提出的解决方案会很快变得非常丑陋。。。如果我决定去读宏路线,你知道有什么好的资源可以让我了解Scheme(特别是Racket)读宏吗?我对它们几乎没有什么经验,但我似乎记得Scheme reader宏在我看来远不如普通的Lisp reader宏强大。特别是:我可以编写一个扩展为读取器宏定义的常规宏吗?或者现在修改reading会不会太晚?Racket有能力进行完整的解析(这太多了),以及CL风格的基于readtable的reader宏(这在这里也不太合适)。相反,最好像往常一样读取文件,然后找到与所需相似的s-expr,并通过向左移动
    :=
    进行转换。但是可以通过
    #%模块来实现这一点,只需创建一个简单的循环,然后将结果发送到通常的循环即可。但是这个循环应该使用真实代码,而不是
    语法规则来完成。好的,因此,如果我正确理解了您的解决方案,我将使用一个常规的
    定义语法
    宏,非常类似于您的
    我的模块begin
    示例,然后我将遍历
    (define-syntax-rule (track E)
      (begin (eprintf "Evaluating: ~s\n" 'E)
             E))
    (x := 1)
    
    #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)