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

递归类型中经eta缩减的genericShow版show定义为何栈溢出?

为什么eta缩减的show = genericShow会引发栈溢出,而eta展开写法却正常?

先看问题中的代码:

定义递归数据类型:

data Chain a = End | Link a (Chain a)

推导Generic实例后,两种Show实例定义:

  • 会栈溢出的eta缩减写法:
derive instance Generic (Chain a) _

instance Show a => Show (Chain a) where
  show = genericShow
  • 正常工作的eta展开写法:
derive instance Generic (Chain a) _

instance Show a => Show (Chain a) where
  show c = genericShow c 

执行logShow $ Link 1 $ Link 2 $ End时,前者直接栈溢出,后者能正确输出结果。

原因分析

问题的核心在于值级循环引用和函数求值的时机差异:

  1. genericShow是基于Generic实例生成的通用序列化函数,对于递归类型Chain a,它处理Link构造器时,会递归调用show来序列化子Chain a值。
  2. 当用eta缩减show = genericShow时,show被直接绑定为genericShow本身。这就形成了一个死循环:genericShow需要调用show,而show就是genericShow,没有机会根据实际的Chain值(比如End)触发终止逻辑。求值时,这个无限递归会直接耗尽栈空间。
  3. 而eta展开的show c = genericShow c是一个匿名函数,每次调用show时才会传入具体的c并执行genericShow。此时genericShow会根据c的构造器分支处理:遇到End就终止递归,遇到Link就分别处理元素和子链,完全符合递归终止的要求,因此不会栈溢出。

说白了,eta缩减写法让show和genericShow形成了无终止条件的循环绑定,而eta展开写法确保每次调用都基于具体的值走正确的递归分支。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 17:22:43