2010-05-01 33 views
6

我经常发现有用的下列类型的增量定义的:增量宏定义可能吗?

(define (foo) (display "bar")) 
(foo) 
;prints bar 
(define foo (let ((bar foo)) 
       (lambda() 
       (display "foo") 
       (bar)))) 

(foo) 
;prints foobar 

如何母材,宏这种类型的增量定义的? 我无法让let-syntax提供相同的功能。

目前我使用plt方案,但希望在不同的lisp实现中看到答案。

编辑:

天真我想做到以下几点:天真的宏

(define-syntax foo 
    (syntax-rules() 
    ((_) (display "bar")))) 

(define-syntax foo 
    (let-syntax ((old-foo (syntax-rules() ((_) (foo))))) 
    (syntax-rules() 
     ((_) (begin 
      (display "foo") 
      (old-foo)))))) 

转换到工作PLT的计划宏:

(require-for-syntax scheme/base) 
(define-syntax foo 
    (syntax-rules() 
    [(foo) (display "bar")])) 
(define-syntax foo 
    (let ([old (syntax-local-value #'foo)]) 
    (lambda (stx) 
     #`(begin #,((syntax-rules() 
       [(_) (begin (display "foo"))]) stx) 
      #,(old #'(_)))))) 
(foo) 

如果我缺少一个更好的方法让我知道。

回答

2

FWIW(这绝对不是太大,因为这是非常靶练习用双脚练习),这里是你如何只用卫生syntax-rules宏为此在PLT的计划:

(define-syntax foo 
    (syntax-rules() 
    [(foo x) (list 'x '= x)])) 
(define-syntax foo 
    (let ([old (syntax-local-value #'foo)]) 
    (compose (syntax-rules() 
       [(_ x ...) (list 'begin x ... 'end)]) 
      old))) 
(printf ">>> ~s\n" (foo (+ 1 2))) 

这不会在一个模块里面工作,只能在REPL上 - 那是一个好的的事情。在模块中也可以做类似的事情,但是如果你想这样做,你也可以使用程序宏(又名syntax-case宏),并在语法级别绑定一个标识符并设置“set!” - 扩大它的价值。仍然不是一个好主意,仍然可能导致眼睛流血,但有些人喜欢伤害自己...

(哦,顺便说一句 - 即使这样做仍然是完全无关的问题的宏是否卫生与否。)

+1

谢谢,我必须包含(需要语法方案/基础)才能在语法阶段定义组合(要在定义语法中定义组合)。你可以评论我的天真方法(添加到问题)没有实施?天气是不是很实际,或者它与现有的语法不一致? – Davorak 2010-05-04 04:09:32

+1

是的,你需要'计划/基地'来组成;但是您可以按任何您想要的方式组合宏函数 - 它们只是从语法到语法的函数,而'syntax-rules'是生成此类函数的方便(通常为第2级)宏。 至于你的幼稚方法,它有一些基本的问题:它试图以某种方式捕获旧的语法,但你不能以这种方式得到它的*值*,所以结果是一个扩展到调用自身的宏。另一个问题是在试图使用'display'来调试东西 - 宏不会*做*它,他们会*扩大*。 – 2010-05-04 04:35:17

+0

谢谢,我知道我无法以这种方式捕捉旧的语法,并且它会扩展到自己。我只是认为它很好地处理了我熟悉的语法,并想知道为什么它存在于函数层次,为什么它不存在于宏观层面,即使似乎没有任何根本阻止编译器以这种方式行事。我试图使用显示作为测试,看看宏是否构建正确,我编辑我的问题翻译我的天真宏到一个工作的PLT计划宏。 – Davorak 2010-05-04 08:35:57

3

使用这个宏,你正在创建最难维护的软件在这个星球上。

编辑:在Common Lisp中是可以的。我不记得我曾经见过它在源代码中使用过。

在Common Lisp社区中,通常将函数或宏的行为称为'advise'或'advice'。一些“建议”工具也可以为宏提供建议。

+0

目前没有我Scheme程序有什么用关键任务,甚至我个人工作流程。此外,我上面的增量定义可以很容易地变成一个Python函数装饰器。所以我的问题措辞的另一种方式是宏装饰可能? – Davorak 2010-05-01 09:28:48

+0

@Davorak:你装饰装饰? – outis 2010-05-01 11:20:02

+0

在python装饰器可以用于装饰器的定义,而我没有机会在我自己的代码中使用它们,我会看到它是如何有用的。只是为了确保我以前的评论清楚我的宏装饰器的意思是一个可以用来装饰另一个宏的宏。 – Davorak 2010-05-01 11:30:26

3

我不认为你可以用宏来做这样的事情。我也没有看到任何尝试。

请注意,宏不只是一些额外的魔术功能!宏是完全不同的。

也许你正在寻找像Common Lisp中的方法组合?

+0

谢谢。你是否也没有看到功能性案例中的观点?或者在Python中装饰器的情况?它有用吗?或者为什么它对宏特别没有用?......现在我已经读了一些关于方法组合的内容,它们似乎提供了Python中装饰器的相同功能。为什么这种抽象级别对函数有用但对宏没有意义? – Davorak 2010-05-01 10:59:25

+0

@Davorak:装饰器与方法组合的功能截然不同。装饰器在定义时执行,而组合方法在调用方法时执行。后者是面向方面编程的重要组成部分。如果有的话,装饰器更类似于宏,但在更有限的情况下使用。 – outis 2010-05-01 11:18:38

+0

你似乎描述的是实现差异而非功能差异。我可以使用装饰器在函数之前,之后或周围运行额外的代码或完全覆盖它。这就像我通过阅读规范所理解的方法组合,您可以使用方法组合在现有函数之前,之后或周围运行额外的代码。 – Davorak 2010-05-01 11:37:49

0

let*怎么样?

(define foobar 
    (let* ((foo (lambda() (display "foo"))) 
      (bar (lambda() (foo) (display "bar")))) 
      bar)) 
+0

谢谢,但我认为你误解了这个问题。我感兴趣的是能够改变全局变量的定义,而上面只是局部的。另外,我的问题是如何处理宏。 – Davorak 2010-05-01 17:25:45

1

我想你可以通过使用不卫生的宏,我相信PLT计划支持。那么你将使用与常规函数完全相同的机制,因为宏将是正常的函数,它发生在S表达式上。

我不知道如何用卫生的宏做这件事,但我很惊讶你不能 - 我会考虑在PLT邮件列表上提问。

+0

谢谢,我会尝试在某个时候询问邮件列表。如果可能在plt中使用不卫生的宏,我仍然会感到惊讶,但很高兴。我试图用defmacro做出答案,但还没有找到答案,虽然我不是defmacro的专家。 – Davorak 2010-05-01 17:33:08

+2

它*可以在PLT中实现 - 它们的关键不在于宏是否卫生,而是具有程序宏观层和一些反映功能。 – 2010-05-04 00:39:54