Haskell 中点积的简单无点实现的结果类型是什么?

问题描述 投票:0回答:1

在 Haskell 中,如果转换两个列表的标准点积,例如

dotProduct :: (Num a) => [a] -> [a] -> a
dotProduct x y = sum . zipWith (*) x y

通过 pointfree.io 这样的 pointfree 工具生成

dotProduct = (sum .) . zipWith (*)

如果我通过统一类型来工作,我充分确信生成的类型确实是

[a] -> [a] -> a
以及必需的类型类。相反,我很困惑为什么我的第一次尝试

dotProduct = sum . zipWith (*)

以如此奇怪的方式失败了。我会理解某种类型错误,但它确实进行了类型检查,并且在 ghci 上,其结果类型是

(Foldable ((->) [c]), Num c, Num [c]) => [c] -> [c]
,我什至无法开始理解。有没有这种类型的示例居民可以传递到点积中?

当我尝试手动运行类型统一算法时,似乎 sum

[a]
的第一个参数应该与
[c] -> [c]
的结尾部分
zipWith (*)
统一。我认为这应该会给出类型错误,但它以某种方式统一了,这就是导致奇怪函数的原因。

haskell pointfree
1个回答
0
投票

当我尝试手动运行类型统一算法时,似乎 sum

[a]
的第一个参数应该与
[c] -> [c]
的结尾部分
zipWith (*)
统一。

正确。

我认为这应该会给出类型错误,但相反它以某种方式统一,这就是导致奇怪函数的原因。

不,为什么?

sum
可以接受任何
t a
,只要
t
是可折叠的,并且
a
是数字类型。在这种情况下我们有

t a = [c] -> [c]
-- i.e., rewriting the function type in prefix notation
t a = (->) [c] [c]
-- ergo
t = (->) [c]
a = [c]

因此这就产生了要求

Foldable ((->) [c])
Num [c]

当然,游戏中的标准实例无法满足此类约束。尽管如此,Haskell 仍然允许人们添加自己的实例。这样做可能会涉及编写奇怪的、人为的实例,但理论上这是可能的,GHC 此时拒绝这一点是错误的。

作为一个人为的示例,以

c = Void
为例,它是没有(非底部)值的空类型。如果我们忽略底部,那么
[c]
就是
[Void]
,它只有一个值(空列表
[]
),所以
[c]
与单位类型
()
同构。

达到同构,约束

Foldable ((->) [c])
Num [c]
变为
Foldable Identity
Num ()
。前一个实例已经存在。后者可以被定义为使得
()
对应于零。可以说,一种零位整数。

© www.soinside.com 2019 - 2024. All rights reserved.