a -> a squ-6ren">
gpt4 book ai didi

haskell - 为什么 ghc 警告 ^2 需要 "defaulting the constraint to type ' Integer'?

转载 作者:行者123 更新时间:2023-12-05 02:36:49 24 4
gpt4 key购买 nike

如果我用 ghc -Wall 编译以下源文件:

main = putStr . show $ squareOfSum 5

squareOfSum :: Integral a => a -> a
squareOfSum n = (^2) $ sum [1..n]

我得到:

powerTypes.hs:4:18: warning: [-Wtype-defaults]
• Defaulting the following constraints to type ‘Integer’
(Integral b0) arising from a use of ‘^’ at powerTypes.hs:4:18-19
(Num b0) arising from the literal ‘2’ at powerTypes.hs:4:19
• In the expression: (^ 2)
In the expression: (^ 2) $ sum [1 .. n]
In an equation for ‘squareOfSum’:
squareOfSum n = (^ 2) $ sum [1 .. n]
|
4 | squareOfSum n = (^2) $ sum [1..n]
| ^^

我理解 (^) 的类型是:

Prelude> :t (^)
(^) :: (Integral b, Num a) => a -> b -> a

这意味着它适用于任何 a^b,前提是 a 是一个 Numb 是一个 积分。我也理解类型层次结构是:

Num --> Integral --> Int or Integer

其中 --> 表示“包含”,前两个是类型类,后两个是类型。

为什么 ghc 没有最终推断出 2 是一个 Int,而不是“将约束默认为 Integer”。为什么 ghc 默认值是什么?将 2 替换为 2::Int 是解决此警告的好方法吗?

最佳答案

在 Haskell 中,数字文字具有多态类型

2 :: Num a => a

这意味着表达式 2 可用于生成任何数字类型的值。例如,所有这些表达式类型检查:

2 :: Int
2 :: Integer
2 :: Float
2 :: Double
2 :: MyCustomTypeForWhichIDefinedANumInstance

从技术上讲,每次我们使用 2 时,我们都必须编写 2::T 来选择我们想要的实际数字类型 T。幸运的是,这通常是不需要的,因为类型推断可以经常从上下文中推断出 T。例如,

foo :: Int -> Int
foo x = x + 2

这里,xInt 因为类型注释,而 + 要求两个操作数具有相同的类型,因此 Haskell 推断2::整数。从技术上讲,这是因为 (+) 有类型

(+) :: Num a => a -> a -> a

然而,有时类型推断无法从上下文中推断出T。考虑这个涉及自定义类型类的示例:

class C a where bar :: a -> String

instance C Int where bar x = "Int: " ++ show x
instance C Integer where bar x = "Integer: " ++ show x

test :: String
test = bar 2

test 的值是多少?好吧,如果 2 是一个 Int,那么我们有 test = "Int: 2"。如果它是一个 Integer,那么我们有 test = "Integer: 2"。如果是另一种数值类型T,我们找不到C T的实例。

此代码本质上是不明确的。在这种情况下,Haskell 强制将无法推导的数字类型默认Integer(程序员可以将此默认值更改为另一种类型,但现在不相关) .因此我们有 test = "Integer: 2"

虽然这种机制会检查我们的代码类型,但它可能会导致意想不到的结果:据我们所知,程序员可能想要 2::Int。因此,GHC 选择默认值,但会发出警告。

在您的代码中,(^) 可以使用指数的任何 Integral 类型。但是,原则上,x ^ (2::Int)x ^ (2::Integer) 可能会导致不同的结果。我们知道情况并非如此,因为我们知道 (^) 的语义,但对于编译器而言,(^) 只是具有该类型的随机函数,它可以表现IntInteger 不同。考虑一下,例如,

a ^ n = if n + 3000000000 < 0 then 0 else 1

n = 2 时,如果我们使用 n::Int,则 if 守卫在 32 位系统上可能为真。使用永不溢出的 n::Integer 时情况并非如此。

在这些情况下,标准解决方案是使用类似 x ^ (2::Int) 的方式解决警告。

关于haskell - 为什么 ghc 警告 ^2 需要 "defaulting the constraint to type ' Integer'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70169536/

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