代码之家  ›  专栏  ›  技术社区  ›  durandaltheta

如何修复此方案协同程序代码以运行在Racket中

  •  1
  • durandaltheta  · 技术社区  · 6 年前

    我试图在Racket LISP中实现协同程序,以用于一个个人学习项目,使用 this accepted answer . 但是,当将我的.rkt文件加载到racket 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是唯一的。

    代码调用(define coroutine)似乎是:

    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))]))                                  
    

    这是我的第一个球拍项目,所以我正在学习 很多 当我走的时候。上面的(begin)试图定义并返回调用对象方法的协程。我确信这个代码片段有很多问题,但是调试器用上面的问题阻止了我,阻止了我以后出现错误:)

    我不是 几乎 熟练的球拍,计划,或口齿不清来解决这个问题,我现在很难理解这个错误。有人能帮我解决这个问题并希望能纠正这个问题,这样我就可以让这个协程代码在Racket中工作了吗?

    1 回复  |  直到 6 年前
        1
  •  4
  •   Leif Andersen    6 年前

    在球拍里, begin 不创建新作用域。 这意味着你在 开始 表单仍在该表单之外的范围内。这也意味着begin不会改变上下文,所以如果您在表达式上下文中, 开始 留着。

    这个 define 表单有(大致)以下语法:

    (define <id> <expr>)
    

    在哪里? <id> 是变量名,并且 <expr> 是一种表达。然而 定义 形式本身就是 一个表达式,所以类似这样的内容是无效的:

    (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 ,谁的阐述是 定义 形式。所以不是用 开始 ,您可以使用 把它变成一个表达式,给你这样的东西:

    (register-message-handler                                  
      msg-type                                                 
      (let ()                                                   
        (define-coroutine (handler-accessor) ....)
        handler-accessor))                                
    

    糟糕的设计决定…我知道。几十年前桥下的水。:(