Haskell带类型约束函数中maxBound类型推导错误如何解决?
Haskell 获取Enum类型maxBound编译报错问题
报错复现
我在学习《Get Programming with Haskell》时尝试扩展书中示例,编写获取Enum类型maxBound的函数时遇到编译报错,代码如下:
rotGen :: (Bounded a, Enum a) => a -> (a, Int) rotGen x = (x, fromEnum (maxBound))
报错信息为:
Could not deduce (Bounded a0) arising from a use of ‘maxBound’
from the context: (Bounded a, Enum a)
我明确问题出在fromEnum (maxBound)无法确定要取哪个Bounded类型的边界,尝试编写fromEnum (maxBound :: a)指定类型也没有生效。
问题根因
默认情况下Haskell函数签名中的类型变量作用域仅覆盖签名本身,函数体内出现的同名a会被编译器识别为全新的类型变量,无法和签名中的入参类型a关联,因此无法解决maxBound的类型歧义问题。
解决方案
以下是基于《Get Programming with Haskell》第15课ROT13 rotator的更简洁实现,已经解决该问题:
-- 需要提前开启以下语言扩展,可写在代码文件头部 -- {-# LANGUAGE ScopedTypeVariables #-} -- {-# LANGUAGE TypeApplications #-} -- 为Enum类型生成编解码函数 rotGen :: forall a . (Bounded a, Enum a) => (a -> a, a -> a) rotGen = (\x -> toEnum ((half + fromEnum x) `mod` max), \x -> toEnum ((upper + fromEnum x) `mod` max)) where max = 1 + fromEnum (maxBound @a) half = max `div` 2 upper = max - half
该实现用到的ScopedTypeVariables扩展支持将签名中显式通过forall声明的类型变量a的作用域扩展到整个函数定义,配合TypeApplications扩展的@a语法,直接指定maxBound对应的类型为入参的泛型类型a,完美解决了类型歧义问题。上述两个扩展属于Haskell的进阶语法特性,新手可以后续逐步学习理解。
内容的提问来源于stack exchange,提问作者zero fish
相关产品推荐
相关产品推荐

