我正在尝试使用this accepted answer中的方案实现在Racket LISP中为个人学习项目实现协程。但是,将我的.rkt文件加载到球拍repl时,出现以下错误:
; 3.rkt:111:18: define: not allowed in an expression context
; in: (define (run-handler) (make-generator (lambda (yield) (send
; (get-dp-data-object key) run))))
似乎在代码的这一部分中抱怨定义:
108 (define-syntax (define-coroutine stx)
109 (syntax-case stx ()
110 ((_ (name . args) . body )
111 #`(define (name . args)
112 (make-generator
113 (lambda (#,(datum->syntax stx 'yield))
114 . body))))))
根据accepted answer here,Scheme不会共享此确切错误,并且在尝试在表达式中定义时对于Racket是唯一的。
调用代码(定义协程)似乎是:
518 ;; Qt-esque connect macro
519 (define-syntax connect-message
520 (syntax-rules ()
521 [(register src-obj-key msg-type dst-obj-key handler)
522 (register-message-handler
523 msg-type
524 (begin
525 (define-coroutine
526 (handler-accessor)
527 (if (eqv? (get-dp-data-object dst-obj-key) #f)
528 #f
529 (send
530 (get-dp-data-object dst-obj-key)
531 handler
532 (get-field args msg))))
533 handler-accessor))]))
这是我的第一个Racket项目,所以我正在学习很多。上面的(开始)试图定义并返回一个调用对象方法的协程。我确定此代码段存在很多问题,但调试器将上述问题拒之门外,使我免于以后出现错误:)
我对Racket,Scheme或LISP的理解不够熟练,目前我几乎无法理解该错误。有人可以帮我解决问题,并希望更正此问题,以便我可以在Racket中使用此协程代码吗?
答案 0 :(得分:4)
在球拍中,begin
不会创建新的范围。 1 这意味着您在begin
表单内定义的任何内容仍在该表单之外的范围内。这也意味着begin不会更改上下文,因此,如果您处于表达式上下文中,则begin
会保留该上下文。
define
格式(大致)具有以下语法:
(define <id> <expr>)
<id>
是变量名,<expr>
是表达式。但是,define
表单本身是不是表达式,因此类似这样的内容是无效的:
(define x (define y 5))
并且因为begin不会更改上下文,所以这也是无效的:
(define x
(begin
(define y 5)
y))
相反,您可以使用let
创建一个新的范围。并且由于let本身是一个表达式,因此可以将其放在define中。因此,您可以编写如下内容:
(define x
(let ()
(define y 5)
y))
现在,x
已按预期绑定到5
。
回到原来的问题,您得到了以下代码:
518 ;; Qt-esque connect macro
519 (define-syntax connect-message
520 (syntax-rules ()
521 [(register src-obj-key msg-type dst-obj-key handler)
522 (register-message-handler
523 msg-type
524 (begin
525 (define-coroutine
526 (handler-accessor)
527 (if (eqv? (get-dp-data-object dst-obj-key) #f)
528 #f
529 (send
530 (get-dp-data-object dst-obj-key)
531 handler
532 (get-field args msg))))
533 handler-accessor))]))
我假设register-message-handler
是一个函数,因此需要一个表达式。但是您有define-coroutine
,详细说明的是define
形式。因此,除了使用begin
之外,您还可以使用let
将其转换为表达式,从而获得如下效果:
(register-message-handler
msg-type
(let ()
(define-coroutine (handler-accessor) ....)
handler-accessor))
1 错误的设计决策...我知道。几十年前的桥下水。 :(