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

Typed Racket中`with-handlers`的异常行为问题及解决咨询

Typed Racket中异常处理的类型检查错误问题解析

问题场景

基础版代码(Typed与非Typed Racket均正常运行)

(with-handlers
    ([exn:fail:contract:divide-by-zero?
      (lambda (e)
        (raise e))])
    (let ([x 0]
          [y 1])
      (display (/ y x))))

运行输出:

/: division by zero

扩展版代码(非Typed正常,Typed报错)

(with-handlers
    ([exn:fail:contract:divide-by-zero?
      (lambda (e)
        (displayln "oops!")
        (raise e))])
    (let ([x 0]
          [y 1])
      (display (/ y x))))

非Typed运行结果:

oops!
/: division by zero

Typed Racket中触发的类型检查错误:

Type Checker: No function domains matched in function application:
Domains: (U (Rec flat (U (Immutable-HashTable flat flat) (Immutable-Vectorof flat) (Pairof flat flat) Boolean Bytes Char Complex Keyword Null String Symbol)) exn) Any
(U (Rec flat (U (Immutable-HashTable flat flat) (Immutable-Vectorof flat) (Pairof flat flat) Boolean Bytes Char Complex Keyword Null String Symbol)) exn)
Arguments: Any
in: (raise e)

原因分析

Typed Racket的类型推断机制在处理多表达式的handler函数时,会丢失异常参数e的具体类型信息:

  • 当handler仅包含(raise e)时,类型检查器能直接推断e是exn:fail:contract:divide-by-zero类型,与raise的参数类型要求匹配。
  • 加入displayln "oops!"后,handler函数的返回类型被推断为Void(displayln返回Void,raise返回Nothing,两者的并类型为Void),此时类型检查器无法保留e的具体异常类型,将其推断为Any。而raise在Typed Racket中要求参数必须是exn类型或特定的“flat”可打印类型,Any不满足该类型约束,因此触发类型检查错误。

解决办法

给handler的lambda表达式显式标注参数e的类型,明确其为exn:fail:contract:divide-by-zero类型,让类型检查器能正确识别参数类型:

(require typed/racket)

(with-handlers
    ([exn:fail:contract:divide-by-zero?
      (lambda ([e : exn:fail:contract:divide-by-zero])
        (displayln "oops!")
        (raise e))])
    (let ([x 0]
          [y 1])
      (display (/ y x))))

这段代码在Typed Racket中可正常运行,输出与非Typed版本一致:

oops!
/: division by zero

内容的提问来源于stack exchange,提问作者Tom Price

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 23:06:17