【问题标题】:Racket: Creating a stream using a macro instead of a functionRacket:使用宏而不是函数创建流
【发布时间】:2021-06-02 18:50:42
【问题描述】:

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

(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: not an identifier, identifier with default, or keyword”。

(create-stream squares using (lambda (x) (* x x)) starting at 5 with increment 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))))

【问题讨论】:

  • 不要剥离define name 部分,而是尝试保持(define name (lambda () (fn i0)) 原样,在其后添加name,看看会发生什么。但你真的应该发布一个关于这一切的新问题。

标签: stream macros racket thunk


【解决方案1】:

我怀疑正在发生的事情是,通过尝试在宏中使用 lambda,它会隐藏 Racket 中的实际 lambda 函数

不,这不正确。

这里的问题是您在绑定位置使用fdelta,在(lambda (f current delta) ...)。这意味着在 (create-stream squares using (lambda (x) (* x x)) starting at 5 with increment 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)))
    ]))

这将使您的代码开始运行,但您的代码中还有其他几个错误。既然这是你的作业,我就交给你了。

【讨论】:

  • 谢谢,这很有帮助。不过,我遇到了一个新错误,所以任何建议都将不胜感激。
  • 那么,您对这个问题的理解是什么?你做了什么?
  • 好吧,我目前解决它的方法是创建一个创建流的辅助函数,然后让我的宏调用它并将其分配给流名称(lambda () (f i0)) .据我所知,宏应该可以直接做到这一点,但我还没有弄清楚如何将它直接包装在我的宏中(define sname (lambda () (f i0))
  • @Chris 请用minimal reproducible example 发布新问题。
  • @Chris 您对问题的编辑使此答案无效。这不是应该如何在 SO 上提出问题的方式。相反,您应该将此问题恢复到以前的状态,并发布带有指向此问题的链接的新问题以作为参考背景。
【解决方案2】:

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

(let ((x 0))
    (define y x))

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

解决方案是翻转定义并将letrec 本地化为define

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

【讨论】:

    猜你喜欢
    • 2017-10-14
    • 2011-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-13
    相关资源
    最近更新 更多