与Haskell类型推断混淆

Ine*_*ept 5 haskell type-inference

我不明白为什么以下功能有效:

isLongerThanN :: Integral n => n -> [a] -> Bool
isLongerThanN n xs = length xs > fromIntegral n
Run Code Online (Sandbox Code Playgroud)

但以下不是:

isLongerThanN' :: Integral n => n -> [a] -> Bool
isLongerThanN' n xs = length xs > n
Run Code Online (Sandbox Code Playgroud)

这引发了错误

Could not deduce (n ~ Int)
    from the context (Integral n)
      bound by the type signature for
                 isLongerThanN' :: Integral n => n -> [a] -> Bool
      at blah.hs:140:1-35
      `n' is a rigid type variable bound by
          the type signature for
            isLongerThanN' :: Integral n => n -> [a] -> Bool
          at blah.hs:140:1
    In the second argument of `(>)', namely `n'
    In the expression: length xs > n
    In an equation for `isLongerThanN'':
        isLongerThanN' n xs = length xs > n
Run Code Online (Sandbox Code Playgroud)

(我可能误解了)

如果有的话,我希望它是另一种方式,因为fromIntegral实际上扩展了变量n的类型.

huo*_*uon 12

考虑不起作用的表达式

isLongerThanN' :: Integral n => n -> [a] -> Bool
isLongerThanN' n xs = length xs > n
Run Code Online (Sandbox Code Playgroud)

n可以是任何整数y类型,因此可以传递一个IntegerWordInt.(>)有类型,Ord a => a -> a -> Bool所以它的左右操作数必须是相同的类型.length xs返回一个Int所以这种类型必须是那样.但是,n可以是任何Integral,不一定Int,所以我们需要某种方式允许n转换为Int.这是什么fromIntegral(事实上​​它也允许n任何Num基本上无关紧要).

我们可以将工作版本扩展为:

toInt :: Integral n => n -> Int
toInt = fromIntegral

isLongerThanN :: Integral n => n -> [a] -> Bool
isLongerThanN n xs = length xs > toInt n
Run Code Online (Sandbox Code Playgroud)

这让我们更清楚地知道我们正在使用一个专门的版本fromIntegral.

(注意,它isLongerThanN n xs = fromIntegral (length xs) > n也有效,因为它允许结果length与类型相匹配n.)

  • 但请注意,您选择转换哪一个会影响结果; 最后一个例子`isLongerThanN(0 :: Word8)[1..256] == False`由于溢出. (2认同)