Stream Racket:使用宏而不是函数创建流

Stream Racket:使用宏而不是函数创建流,stream,macros,racket,thunk,Stream,Macros,Racket,Thunk,我目前正在尝试使用宏创建流,如下所示: (define-syntax create-stream (syntax-rules (using starting at with increment ) [(create-stream name using f starting at i0 with increment delta) (letrec ([name (lambda (f current delta) (c

我目前正在尝试使用宏创建流,如下所示:

(define-syntax create-stream
  (syntax-rules (using starting at with increment )
    [(create-stream name using f starting at i0 with increment delta)
     (letrec 
       ([name (lambda (f current delta) 
                      (cons current (lambda () (name (f (+ current delta) delta)))))])
       (lambda () (name f i0 delta)))
    ]))
但是,当我稍后尝试将以下lambda函数传递给它时,会出现编译错误,该函数表示“lambda:不是标识符、带有默认值的标识符或关键字”

(使用(λ(x)(*x))从5开始以增量2创建流方块)

我怀疑的是,通过尝试在宏中使用lambda,它在Racket中隐藏了实际的lambda函数。如果这是真的,我想知道在不使用lambda的情况下如何创建流,因为据我所知,需要在某个地方有一个函数来创建所述流

这也是一个家庭作业问题,所以我必须使用宏。我创建流的等效函数是:

(define create-stream
  (letrec ([name (lambda (f current delta) (cons current (lambda () (name (f (+ current delta) delta)))))])
    (lambda () (name f i0 delta))))
我怀疑正在发生的事情是,试图在宏中使用lambda,它在Racket中隐藏了实际的lambda函数

不,那不对

这里的问题是,您在绑定位置使用
f
delta
(lambda(f当前delta))。这意味着在展开
(使用(lambda(x)(*x))从5开始以增量2创建流方块)
后,您将得到如下代码:

(lambda ((lambda (x) (* x x)) current 2) ...)
这显然是一个语法错误

您可以通过使用DrRacket中的宏步进器自己看到这一点

修复方法是将标识符重命名为其他名称。例如:

(define-syntax create-stream
  (syntax-rules (using starting at with increment )
    [(create-stream name using f starting at i0 with increment delta)
     (letrec 
       ([name (lambda (f* current delta*) 
                      (cons current (lambda () (name (f* (+ current delta*) delta*)))))])
       (lambda () (name f i0 delta)))
    ]))

这将使您的代码开始运行,但您的代码中还有其他几个bug。因为这是你的家庭作业,我将把它们留给你。

你当前的问题基本上归结为这个(坏的)代码

这并不等同于
(定义y 0)
-
y
的定义是let绑定的本地定义

解决方案是翻转定义,使
letrec
位于
define
的本地:

(define name
    (letrec (... fn definition ...)
        (lambda () (fn i0))))

谢谢,这很有帮助。不过,我遇到了一个新的bug,所以如果您能给我一些建议,我将不胜感激。那么,您对这个问题的理解是什么?你做了什么?好吧,我现在解决这个问题的方法是创建一个帮助函数来创建流,然后让我的宏调用它并将它分配给流名称
(lambda()(f i0))
。据我所知,宏应该能够直接完成这项工作,但我还没有弄清楚如何将它直接包装到我的宏
(define sname(lambda()(f i0))
@Chris请用please发布新问题。@Chris您对问题的编辑将使此答案无效。这不是在SO上提问的方式。相反,您应该将此问题恢复到以前的状态,并发布新问题,并带有此问题的链接,以供参考背景。而不是剥离
d定义名称
部分,试着保持
(定义名称(lambda()(fn i0))
不变,在其后面添加
名称
,看看会发生什么。但你真的应该发布一个新的问题。
(define name
    (letrec (... fn definition ...)
        (lambda () (fn i0))))