Haskell无点风格点积实现的类型问题及异常类型解析
为什么
sum . zipWith (*)能通过类型检查,且是否存在合法输入? 首先拆解类型推导过程:
明确基础函数的类型:
zipWith (*) :: Num c => [c] -> [c] -> [c]:柯里化后等价于[c] -> ([c] -> [c]),即接受第一个列表后,返回一个接受第二个列表并计算对应元素乘积的函数。sum :: (Foldable t, Num b) => t b -> b:接受一个可折叠容器t b,返回容器内元素的和。
用
.组合两个函数时的类型匹配逻辑:- 组合符
.的类型是(b -> c) -> (a -> b) -> a -> c,这里需要zipWith (*)的输出(即[c] -> [c])作为sum的输入。 - 这意味着
sum的输入类型t b必须匹配[c] -> [c],因此推导得出:- 容器类型
t是函数类型(->) [c](即t x = [c] -> x) - 容器内元素类型
b是[c]
- 容器类型
- 最终组合后的函数类型整合了所有约束:
(Foldable ((->) [c]), Num c, Num [c]) => [c] -> [c]
- 组合符
这个类型能通过检查的原因是:Haskell类型检查器仅验证约束的语法合法性,不会强制要求当前环境已存在对应实例——只要理论上可以定义这些实例,类型就是合法的。
是否存在符合该类型的输入?
可以构造出满足条件的环境,但标准库没有默认提供所需实例,需要手动定义:
定义
Num [c]实例:
为列表实现元素级别的Num操作:instance Num c => Num [c] where xs + ys = zipWith (+) xs ys xs * ys = zipWith (*) xs ys negate = map negate fromInteger n = [fromInteger n] abs = map abs signum = map signum定义
Foldable ((->) [c])实例:
为函数类型定义一个退化的Foldable实例(仅满足类型约束,无实际业务意义):instance Foldable ((->) r) where foldr _ z _ = z -- 忽略输入函数,直接返回初始值z foldMap _ _ = mempty
在这个环境下,sum . zipWith (*)就可以接受输入:
-- 输入[1,2,3],返回初始值0对应的列表形式[0] (sum . zipWith (*)) [1,2,3] :: [Int] -- 输出: [0]
需要注意的是,这种自定义实例更多是类型系统层面的实验,实际开发中标准的无点风格点积(sum .) . zipWith (*)才是符合直觉、有实际意义的实现。
内容的提问来源于stack exchange,提问作者hurozen
相关产品推荐
相关产品推荐

