"fromIntegral" "Could not deduce"错误



我正在努力学习Haskell,我已经使这个函数应该(我还没有实际测试过)读取变量:

import Data.Bits
import Data.Binary
getNum :: Get Int
getNum = do
    l <- getWord8
    let v = fromIntegral (clearBit l 7) :: Int
    if testBit l 7
        then do m <- getNum
                return $ v .|. shiftL m 7
        else return v

它编译得很好,但我希望它能够读取任何类型的整数,而不仅仅是Int,所以我把它改成了:

import Data.Bits
import Data.Binary
getNum :: (Bits a, Integral a) => Get a
getNum = do
    l <- getWord8
    let v = fromIntegral (clearBit l 7) :: a
    if testBit l 7
        then do m <- getNum
                return $ v .|. shiftL m 7
        else return v

不幸的是,这会给我以下错误:

Could not deduce (Num a2) arising from a use of ‘fromIntegral’
from the context (Bits a, Integral a)
  bound by the type signature for
             getNum :: (Bits a, Integral a) => Get a
  at test.hs:12:11-39
Possible fix:
  add (Num a2) to the context of
    an expression type signature: a2
    or the inferred type of v :: a1
    or the type signature for getNum :: (Bits a, Integral a) => Get a
In the expression: fromIntegral (clearBit l 7) :: a
In an equation for ‘v’: v = fromIntegral (clearBit l 7) :: a
In the expression:
  do { l <- getWord8;
       let v = ...;
       if testBit l 7 then
           do { m <- getNum;
                .... }
       else
           return v }

我真的弄不清楚错误信息是想告诉我什么,我找不到任何结论性的搜索。有人可以向我解释为什么这个错误发生和如何修复它?

:: afromIntegral行中删除:

import Data.Bits
import Data.Binary
getNum :: (Bits a, Integral a) => Get a
getNum = do
    l <- getWord8
    let v = fromIntegral (clearBit l 7)
    if testBit l 7
        then do m <- getNum
                return $ v .|. shiftL m 7
        else return v

解释

暂时再假设下面这行:

    let v = fromIntegral (clearBit l 7) :: a

此时,a是另一个独立类型变量,与(Bits a, Integral a) => Get a中的a无关。因此,a没有NumBit约束,尽管类型检查器应该正确,因为您更改了return v

然而,由于您缺少约束,它假设您实际上知道您在做什么,并假设一个任意类型。因为fromIntegral 需要一个Integral实例,所以它失败了。如果您在本地再次添加这些约束,它将再次编译:

let v = fromIntegral (clearBit l 7) :: (Integral a) => a

但是,此时a并不是函数签名中的类型变量。为此,您将需要ScopedTypeVariables扩展。但是更好的做法是,只需放弃局部表达式签名,因为GHC将正确地推断类型。

最新更新