为何η规约无法作用于类型别名?能否简化嵌套类型定义?
为什么η规约无法作用于类型别名?如何实现目标类型定义?
一、η规约不适用于类型别名的原因
GHC中的类型别名是完全饱和的语法糖,它们的本质是直接展开为目标类型,而非一等类型构造器。η规约(将未饱和构造器视为接受剩余参数的函数)仅适用于真正的类型构造器(如数据类型、类型家族),而类型别名在使用时必须被完全应用所有参数——GHC不会自动为未饱和的类型别名补全缺失参数,这是设计上的限制:既避免了类型推断的歧义,也保证了类型别名的透明性。
二、实现目标的可行方案
你的需求核心是使用未饱和的类型组合子,普通类型别名无法满足,但结合不饱和类型家族的特性,有两种可行方案:
1. 不饱和类型家族(推荐,需GHC 9.2+)
开启UnsatTypeFamilies扩展后,可定义无需完全饱和的类型家族,直接作为组合子使用:
{-# LANGUAGE UnsatTypeFamilies #-} {-# LANGUAGE TypeFamilies #-} -- 定义未饱和的类型组合子C type family C a b c where C a b c = a (b c) -- 定义D和E,支持未饱和类型家族作为参数 type family D a b where D a b = a b b type E = D C -- V系列类型定义可正常工作 type V = VList type V2 a = V (V a) type V4 = E V2 -- 等价于C V2 V2,接受a后展开为V2 (V2 a) type V8 = E V4 type V16 = E V8 type V32 = E V16 -- 简洁的嵌套类型定义 type Vector25 = C (C V16 V8) V Empty -- 展开后自动得到:V16 (V8 (V Empty))
2. 旧版GHC兼容方案(数据类型+Eval类型家族)
若无法升级GHC,可通过数据类型表示组合结构,再用Eval类型家族手动展开:
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE PolyKinds #-} -- 用数据类型标记组合操作 data C a b c data D a b data E -- 定义Eval家族处理展开逻辑 type family Eval t where Eval (C a b c) = Eval a (Eval (Eval b c)) Eval (D a b) = Eval a (Eval b) (Eval b) Eval E = Eval (D C) Eval (V x) = VList (Eval x) Eval V = VList Eval V2 = \x -> VList (VList x) Eval V4 = \x -> Eval V2 (Eval V2 x) Eval V8 = \x -> Eval V4 (Eval V4 x) Eval V16 = \x -> Eval V8 (Eval V8 x) Eval V32 = \x -> Eval V16 (Eval V16 x) Eval Empty = Empty -- 使用时需包裹在Eval中 type Vector25 = Eval (C (C V16 V8) V Empty)
这种方案需要手动维护展开规则,不如不饱和类型家族简洁,但可在旧版本GHC上运行。
关键说明
普通类型组合操作符之所以无效,是因为它们本质仍是需要完全饱和的类型别名,无法保留未饱和状态;而不饱和类型家族允许类型构造器以未饱和形式存在,直到被完全应用时才展开,这正是解决你问题的核心。
内容的提问来源于stack exchange,提问作者Ashok Kimmel
相关产品推荐
相关产品推荐

