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

引入含`raise'函数的Hy宏时,`require'阶段触发`raise'执行异常

解决Hy宏中raise偶发触发的问题

我来帮你拆解这个偶发异常的问题,核心根源其实是宏的参数声明语法出错了,导致宏展开后的代码完全不符合你的预期。

问题到底出在哪?

你写的宏定义是这样的:

(defmacro assert [a [b True] [message None]]
  `(unless (= ~a ~b)
     (raise (AssertionError (or ~message ~a)))))

这里的参数列表[a [b True] [message None]]不是设置默认参数的正确写法——在Hy里,这种写法属于参数解构,意思是:

  • 这个宏需要接收3个参数:第一个是a,第二个是能拆成两个元素的列表(分别绑定给变量b和True),第三个是能拆成两个元素的列表(分别绑定给变量message和None)

当你调用(assert True)时,只传了第一个参数,后两个参数默认是nil。Hy尝试把nil解构为[b True]时,会出现非预期的绑定(比如b被赋值为nil),这时候宏展开后的代码会变成:

(unless (= True nil)
  (raise (AssertionError (or None True))))

显然(= True nil)是False,unless条件成立,自然就触发了raise,抛出AssertionError: True。

至于你说的“偶发现象”,大概率是Hy解析器处理错误解构时的不稳定行为(比如偶尔缓存了错误的宏展开结果,或者解析时的临时容错逻辑),但核心问题还是参数声明的语法错误。

正确的宏写法

在Hy中,给宏(或函数)设置可选默认参数,必须用&optional关键字来声明。修正后的宏定义应该是:

(defmacro assert [a &optional [b True] [message None]]
  `(unless (= ~a ~b)
     (raise (AssertionError (or ~message ~a)))))

&optional会告诉Hy:后面的[b True]和[message None]是可选参数,调用时没传对应值的话,就用后面的字面量当默认值。

验证修正后的代码

按照你的步骤重新测试:

  1. 把修正后的宏写入a.hy:
    echo '(defmacro assert [a &optional [b True] [message None]] `(unless (= ~a ~b) (raise (AssertionError (or ~message ~a)))))' > a.hy
    
  2. 保持b.hy内容不变:
    echo '(require a [assert])' > b.hy
    echo '(assert True)' >> b.hy
    
  3. 执行hy b.hy,此时宏展开后的代码是:
    (unless (= True True)
      (raise (AssertionError (or None True))))
    
    因为(= True True)是True,unless条件不成立,不会执行raise,也就不会再抛出异常了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 21:12:28