gpt4 book ai didi

从当前签名或另一个函数返回类型获取时,Haskell 类型的处理方式不同

转载 作者:行者123 更新时间:2023-12-02 21:44:56 24 4
gpt4 key购买 nike

我按照 this answer 中的建议开始学习 Haskell 。所以我只是实现简单的列表函数,我偶然发现了编译器行为的差异,我无法向自己解释:

-- Impl 1
elementAt :: (Integral b) => [a] -> b -> a
elementAt xs id = xs !! (fromIntegral(id-1))

-- Impl 2
elementAt' :: (Num b) => [a] -> b -> a
elementAt' xs id = xs !! (id-1)

带有以下签名:

fromIntegral :: (Integral a, Num b) => a -> b
(!!) :: [a] -> Int -> a

我仅在第二个实现 elementAt' 时收到错误。

Could not deduce (b ~ Int)
from the context (Num b)

如果我理解正确的话,这意味着运算符 (!!) 期望一个 Int 实例作为其第二个参数(从签名中可以看出),但我们只保证提供的参数是符合 Num 类型类(从 elemenAt' 签名推断),它比 Int 更宽。

考虑到这一点,我不明白为什么第一个实现实际上有效,因为知道 fromIntegral 还返回一个仅符合 Num 类型类的值。

最佳答案

fromIntegral 返回Num 类的任何 实例。也就是说,无论您需要什么实例,它都会知道如何生成它。这就是类型变量的想法,它基本上是函数调用者可以选择的额外编译时参数。这就是 elemAt 起作用的原因:编译器知道我们需要 Int,因此它告诉 fromIntegral,后者知道要做什么。

但是,因此,如果定义一个带有签名Num b => ...的函数,您还需要允许调用者输入他们选择的任何类型对于 b,前提是它位于 Num 类中。在这种情况下,您无法请求特定实例Int,但需要获取调用者提供给您的任何内容。这就是区别。

事实上,Num b => [a] -> b -> a 不是您可以有效定义此函数的签名。如何通过复数,甚至无限维矩阵或其他什么来索引列表?你可以做的是Integral b => [a] -> b -> a

关于从当前签名或另一个函数返回类型获取时,Haskell 类型的处理方式不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19679276/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com