You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Racket代码报错:lhs未绑定标识符问题排查求助

解决Racket解释器中的lhs: unbound identifier错误

你遇到的lhs: unbound identifier错误,本质是代码中多处匹配规则、结构定义的不一致导致的,以下是具体问题和修正方案:

1. and/or表达式的Parse规则错误

你的parse函数中,and和or的匹配模式是(list 'and exps)和(list 'or exps),这只能匹配两个元素的列表(比如(and (list #t #f))),但实际合法的and/or表达式是多个元素(比如(and #t #f #t)),会被错误匹配到最后的函数应用规则,进而引发后续错误。

修正方案:将模式改为匹配任意数量的子表达式:

[(list 'and exps ...)
 (and-exp (map parse exps))]
[(list 'or exps ...)
 (or-exp (map parse exps))]

2. let-exp的Parse逻辑冗余

你的parse函数中,let表达式的ids被用(map parse id)处理,将符号转换为var-exp,但let的绑定名应该直接用符号,不需要解析为表达式结构,冗余处理可能引发匹配异常。修正后简化逻辑:

[(list 'let (list (list id val) ...) body)
 (let-exp id (map parse val) (parse body))]

同时对应的eval规则调整为直接使用符号列表:

[(let-exp (list id ...) (list val ...) body)
 (let ([vars (map cons id (map (lambda (v) (eval v env)) val))])
   (eval body (append vars env)))]

3. load-defs函数功能错误

你的load-defs函数返回的是函数名列表,但repl中需要的是键值对形式的环境,正确的load-defs应该解析文件中的定义并生成合法环境:

(define (load-defs filename)
  (let* ([sexps (file->list filename)]
         [defs (map (lambda (sexp)
                      (match sexp
                        [(list 'define (list id args ...) body)
                         (cons id (eval (desugar (parse sexp)) '()))]
                        [(list 'define id val)
                         (cons id (eval (desugar (parse val)) '()))]))
                    sexps)])
    defs))

4. 完善desugar函数的递归处理

原desugar函数只处理了部分表达式类型,需要补充所有表达式的递归展开,确保嵌套表达式能正确被处理:

(define (desugar exp)
  (match exp
    ((arith-exp op lhs rhs)
     (arith-exp op (desugar lhs) (desugar rhs)))
    ((let-exp ids vals body)
     (let-exp ids (map desugar vals) (desugar body)))
    ((lambda-exp ids body)
     (foldr (lambda (id lexp) (lambda-exp id lexp))
            (desugar body)
            ids))
    ((app-exp f args)
     (foldl (lambda (arg fexp) (app-exp fexp arg))
            (desugar f)
            (map desugar args)))
    ((sub-exp lhs rhs)
     (sub-exp (desugar lhs) (desugar rhs)))
    ((eq-exp lhs rhs)
     (eq-exp (desugar lhs) (desugar rhs)))
    ((and-exp operands)
     (and-exp (map desugar operands)))
    ((or-exp operands)
     (or-exp (map desugar operands)))
    ((if-exp bool true-exp false-exp)
     (if-exp (desugar bool) (desugar true-exp) (desugar false-exp)))
    (_ exp)))

修正后的完整代码

#lang racket

(provide parse
         desugar
         eval
         load-defs
         repl)

(struct eq-exp (lhs rhs) #:transparent)
(struct and-exp (operands) #:transparent)
(struct or-exp (operands) #:transparent)
(struct int-exp (val) #:transparent)
(struct arith-exp (op lhs rhs) #:transparent)
(struct var-exp (id) #:transparent)
(struct let-exp (ids vals body) #:transparent)
(struct lambda-exp (id body) #:transparent)
(struct app-exp (fn arg) #:transparent)
(struct fun-val (id body env) #:transparent)
(struct bool-exp (val) #:transparent)
(struct if-exp (bool-exp true-exp false-exp) #:transparent)
(struct sub-exp (lhs rhs) #:transparent)


(define (parse sexp)
  (match sexp
    [(? integer?)
     (int-exp sexp)]
    [(? boolean?)
     (bool-exp sexp)]
     
    [(list '-' lhs rhs)
     (sub-exp (parse lhs) (parse rhs))]
    [(list '= lhs rhs)
     (eq-exp (parse lhs) (parse rhs))]
    [(list (and op (or '+ '*)) lhs rhs)
     (arith-exp (symbol->string op) (parse lhs) (parse rhs))]
    [(list 'and exps ...)
     (and-exp (map parse exps))]
    [(list 'or exps ...)
     (or-exp (map parse exps))]
    [(? symbol?)
     (var-exp sexp)]
    [(list 'let (list (list id val) ...) body)
     (let-exp id (map parse val) (parse body))]
    [(list 'lambda (list ids ...) body)
     (lambda-exp ids (parse body))]
    [(list 'if bool true-expr false-expr)
     (if-exp (parse bool) (parse true-expr) (parse false-expr))]
    [(list 'define (list id args ...) body)
     (lambda-exp args (parse body))]
    [(list 'define id val)
     (parse val)]
    [(list f args ...)
     (app-exp (parse f) (map parse args))]
    [_ (error (format "Can't parse: ~a" sexp))]))

(define (desugar exp)
  (match exp
    ((arith-exp op lhs rhs)
     (arith-exp op (desugar lhs) (desugar rhs)))
    ((let-exp ids vals body)
     (let-exp ids (map desugar vals) (desugar body)))
    ((lambda-exp ids body)
     (foldr (lambda (id lexp) (lambda-exp id lexp))
            (desugar body)
            ids))
    ((app-exp f args)
     (foldl (lambda (arg fexp) (app-exp fexp arg))
            (desugar f)
            (map desugar args)))
    ((sub-exp lhs rhs)
     (sub-exp (desugar lhs) (desugar rhs)))
    ((eq-exp lhs rhs)
     (eq-exp (desugar lhs) (desugar rhs)))
    ((and-exp operands)
     (and-exp (map desugar operands)))
    ((or-exp operands)
     (or-exp (map desugar operands)))
    ((if-exp bool true-exp false-exp)
     (if-exp (desugar bool) (desugar true-exp) (desugar false-exp)))
    (_ exp)))

(define (eval expr [env '()])
  (match expr
    [(int-exp val) val]
    [(bool-exp val) val]
    [(arith-exp "+" lhs rhs) (+ (eval lhs env) (eval rhs env))]
    [(arith-exp "*" lhs rhs) (* (eval lhs env) (eval rhs env))]
    [(var-exp id)
     (let ([pair (assoc id env)])
       (if pair (cdr pair) (error (format "~a not bound!" id))))]
    [(let-exp (list id ...) (list val ...) body)
     (let ([vars (map cons id (map (lambda (v) (eval v env)) val))])
       (eval body (append vars env)))]
    [(lambda-exp id body)
     (fun-val id body env)]
    [(sub-exp lhs rhs) (- (eval lhs env) (eval rhs env))]
    [(eq-exp lhs rhs) (= (eval lhs env) (eval rhs env))]
    [(and-exp operands) (andmap (lambda (operand) (eval operand env)) operands)]
    [(or-exp operands) (ormap (lambda (operand) (eval operand env)) operands)]
    [(app-exp f arg)
     (match-let ([(fun-val id body clenv) (eval f env)]
                 [arg-val (eval arg env)])
       (eval body (cons (cons id arg-val) clenv)))]
    [(if-exp bool true-expr false-exp)
     (if (eval bool env)
         (eval true-expr env)
         (eval false-expr env))]
    [_ (error (format "Can't evaluate: ~a" expr))]))

(define (load-defs filename)
  (let* ([sexps (file->list filename)]
         [defs (map (lambda (sexp)
                      (match sexp
                        [(list 'define (list id args ...) body)
                         (cons id (eval (desugar (parse sexp)) '()))]
                        [(list 'define id val)
                         (cons id (eval (desugar (parse val)) '()))]))
                    sexps)])
    defs))

(define (repl [filename #f])
  (let loop ([env (if filename (load-defs filename) '())])
    (let ([stx (desugar (parse (read)))])
      (when stx
        (with-handlers ([exn? (lambda (e) (displayln (exn-message e)))])
          (println (eval stx env)))
        (loop env)))))

(repl) ; Start the REPL

额外优化

  • 添加了define表达式的parse规则,支持解析文件中的函数和变量定义
  • 在repl中加入异常处理,避免单个错误导致REPL崩溃
  • 完善了所有表达式类型的递归处理,确保嵌套结构能正确解析和求值

内容的提问来源于stack exchange,提问作者Ibne Nahian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 23:09:51