如何告知Haskell编译器两种类型兼容?
问题解答
你需要手动推导并指定精确类型,编译器无法自动帮你完成这种特定的类型合一操作,原因和推导过程如下:
为什么编译器无法自动合一?
你最初写的类型签名是最一般的多态类型,其中b和c是独立的多态变量。Haskell编译器的类型推导只会维护这些变量的多态性,生成最通用的类型签名,而不会自动将它们收缩到特定的类型来满足“自组合”的约束——这种约束属于特定的单态化需求,超出了编译器自动推导的范围。
手动推导精确类型
你的需求是让(apply_to_f f)的类型为((a -> a) -> a) -> ((a -> a) -> a),即接受一个(a->a)->a类型的函数,返回同类型的函数。我们可以基于原函数的实现反向推导:
- 原函数实现为
apply_to_f f = \g -> \h -> h (g f),当g的类型是(a->a)->a时,g f的结果类型是a,因此原类型中的b必须等于a。 - 接下来,
apply_to_f f g是一个接受h并返回h (g f)的函数,我们要求这个函数的类型是(a->a)->a——也就是h的类型是a->a,返回值是a,对应原类型中的c也等于a。
将b=a和c=a代入原类型签名,就能得到满足需求的精确类型:
apply_to_f :: (a -> a) -> ((a -> a) -> a) -> ((a -> a) -> a) apply_to_f f = \g -> \h -> h (g f)
验证一下:这个类型下,(apply_to_f f)接受g :: (a->a)->a,返回的函数接受h :: a->a,最终返回h (g f) :: a,完全符合“自组合”的要求——你可以把(apply_to_f f)和自身组合,因为输入输出类型一致。
关于“模糊类型”的尝试
你提到的用类型变量表示约束的方法行不通,是因为Haskell的基础类型系统无法直接表达这种“自组合”的等式约束(虽然GADTs或类型族可以实现类似功能,但对于这个场景来说完全没必要,手动推导是最简洁的方案)。
内容的提问来源于stack exchange,提问作者Theo H
相关产品推荐
相关产品推荐

