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

Haskell中error函数多次打印Exception的原因及相关疑问

Haskell嵌套调用error函数的异常打印问题

现象展示

单次调用error:

Prelude> error ""
*** Exception: 
CallStack (from HasCallStack):
  error, called at <interactive>:3:1 in interactive:Ghci1

两次嵌套调用:

Prelude> error (error "")
*** Exception: *** Exception: 
CallStack (from HasCallStack):
  error, called at <interactive>:2:8 in interactive:Ghci1

三次及更多嵌套调用时,会打印对应数量的*** Exception:提示。

我编写了如下函数,可按输入次数打印异常提示:

printException n = foldr (\c r -> c error r) id (replicate n (.)) ""

同时存在疑问:为何until (const False) error ""不会无限打印Exception?

问题解答

1. 嵌套调用error为何出现多份Exception提示

Haskell采用按需求值策略,调用error (e)时必须先求值参数e,才能完成外层error的调用流程。

以error (error "")为例:

  • 外层error需要获取参数值,因此先触发内层error ""的求值,内层error抛出第一个异常;
  • 外层error在尝试获取参数时捕获到该异常,自身也会抛出异常;
  • GHCi处理未捕获的异常链时,会依次打印每一层触发的异常提示,因此嵌套n层就会出现n份*** Exception:。

你写的printException n本质是生成n层嵌套的error调用(比如n=3时等价于error (error (error ""))),因此会打印对应次数的异常提示。

2. 为何until (const False) error ""不会无限打印

先看until的标准定义:

until :: (a -> Bool) -> (a -> a) -> a -> a
until p f x = if p x then x else until p f (f x)

这里p是const False,永远返回False,但实际只会触发一次异常:

  • 第一次执行f x(即error "")时,会立即抛出异常,直接中断整个求值过程;
  • 异常抛出后,程序没有机会执行到递归分支until p f (f x),因此不会触发后续的error调用,自然不会无限打印异常提示。

内容的提问来源于stack exchange,提问作者Damian Rafael Lattenero

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 14:25:24