"无法推断"来自"fromIntegral"的错误

Mik*_*sen 0 haskell

我正在尝试学习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
Run Code Online (Sandbox Code Playgroud)

它编译得很好,但我希望这能够读取任何类型的整数,而不仅仅是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
Run Code Online (Sandbox Code Playgroud)

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

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 }
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚错误消息试图告诉我什么,我找不到任何确凿的搜索它.有人可以向我解释为什么会出现这个错误以及如何解决它?

Zet*_*eta 6

只需删除:: 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
Run Code Online (Sandbox Code Playgroud)

说明

再假设以下一行:

    let v = fromIntegral (clearBit l 7) :: a
Run Code Online (Sandbox Code Playgroud)

此时,a是另一个独立的类型变量,与afrom 无关(Bits a, Integral a) => Get a.因此,a没有NumBit约束,虽然类型检查器应该正确,因为你以后return v.

但是,由于您缺少约束,因此它假定您实际知道自己在做什么并假定为任意类型.由于fromIntegral 需要Integral情况下,它会失败.如果在本地再次添加这些约束,它将再次编译:

let v = fromIntegral (clearBit l 7) :: (Integral a) => a
Run Code Online (Sandbox Code Playgroud)

但是,a此时不是函数签名中的类型变量.你需要这个ScopedTypeVariables扩展名.但更好的是,只需废弃本地表达式签名,因为GHC会正确地推断出类型.