我正在努力学习Haskell并且我已经完成了这个功能(我还没有真正测试过它)阅读varints:
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 }
我无法弄清楚错误消息试图告诉我的内容,但我无法找到任何结论性的搜索结果。有人可以向我解释为什么会出现这种错误以及如何解决它?
答案 0 :(得分:6)
只需从:: a
行中删除fromIntegral
:
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
是另一个独立的类型变量,与a
中的(Bits a, Integral a) => Get a
无关。因此,a
没有Num
或Bit
约束,但类型检查器应该正确,因为您稍后return v
。
但是,由于您缺少约束,因此它假定您实际知道自己在做什么并假设任意类型。由于fromIntegral
需要 Integral
实例,因此失败。如果在本地再次添加这些约束,它将再次编译:
let v = fromIntegral (clearBit l 7) :: (Integral a) => a
但是,此时a
不是函数签名中的类型变量。您需要ScopedTypeVariables
扩展名。但更好的是,只需废弃本地表达式签名,因为GHC会正确地推断出类型。