如何在无符号类型上使用Haskell的按位函数(例如,`Word8`,`Word16`)?

时间:2014-11-25 03:58:17

标签: haskell bit-manipulation

我可以做些什么(如果有的话),以便能够使用Data.Bits(例如clearBitsetBit)中无符号类型的函数,即Word8Word16?目前,我收到以下错误:

Couldn't match expected type ‘Int’ with actual type ‘Word8’

我将执行大量这些操作,因此fromIntegral并不理想。

有什么建议吗?

更新2: 这就是我需要的:

testBitW :: (Bits a, Integral b) => a -> b -> Bool
testBitW a i = testBit a (fromIntegral i)

更新:

我拉着我的头发试图让下面的代码进行编译。令人费解的是,如果直接输入GHCi,相同的代码工作正常(运行:t根据我的定义提供相同的隐含类型签名)。

testBitW :: (Integral a, Integral b) => a -> b -> Bool
testBitW a i = testBit (fromInteger $ toInteger a) (fromInteger $ toInteger i)

我一直收到以下两个错误。使用fromIntegral代替fromInteger $ toInteger会导致相同的错误......

test.hs:119:16:
    Could not deduce (Bits a0) arising from a use of ‘testBit’
    from the context (Integral a1, Integral a)
      bound by the inferred type of
               testBitW :: (Integral a1, Integral a) => a -> a1 -> Bool
      at test.hs:119:1-78
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Bits Word16 -- Defined in ‘GHC.Word’
      instance Bits Word32 -- Defined in ‘GHC.Word’
      instance Bits Word64 -- Defined in ‘GHC.Word’
      ...plus 9 others
    In the expression:
      testBit (fromInteger $ toInteger a) (fromInteger $ toInteger i)
    In an equation for ‘testBitW’:
        testBitW a i
          = testBit (fromInteger $ toInteger a) (fromInteger $ toInteger i)

test.hs:119:25:
    Could not deduce (Num a0) arising from a use of ‘fromInteger’
    from the context (Integral a1, Integral a)
      bound by the inferred type of
               testBitW :: (Integral a1, Integral a) => a -> a1 -> Bool
      at test.hs:119:1-78
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Num Double -- Defined in ‘GHC.Float’
      instance Num Float -- Defined in ‘GHC.Float’
      instance Integral a => Num (GHC.Real.Ratio a)
        -- Defined in ‘GHC.Real’
      ...plus 11 others
    In the expression: fromInteger
    In the first argument of ‘testBit’, namely
      ‘(fromInteger $ toInteger a)’
    In the expression:
      testBit (fromInteger $ toInteger a) (fromInteger $ toInteger i)
Failed, modules loaded: none.

2 个答案:

答案 0 :(得分:3)

导入Data.Word会将Bits Word8等实例纳入范围。

虽然从您的错误中看起来您正在谈论第二个参数,例如setBit,指定为Int。如果要使用Word s指定位偏移量,则必须使用fromInteger . toInteger。您可以根据上下文以某种方式抽象出来。

更新

在这种情况下,表单“无法推断......”的错误是编译器关于所需类型签名的强提示。以下是如何解决这个问题。

首先,testBit的类型是什么?

> :t testBit
testBit :: Bits a => a -> Int -> Bool

所以我们知道第二个参数需要是Int(不是Integer!),但第一个参数可以是任何带有Bits实例的类型。转换为Int的最常见转换是通过Integer

> :t \x -> (fromInteger . toInteger $ x) :: Int
\x -> (fromInteger . toInteger $ x) :: Int
  :: Integral s => s -> Int

因此,我们需要了解有关testBitW函数的每个参数的一件事:第一个需要是Bits的实例,第二个是Integral的实例。 (我们需要将第一个参数转换为Int,实际上这样做几乎肯定是一个错误。)

如果有疑问,我们可以让编译器推断约束,这通常会给你最一般的类型签名:

> let testBitW a i = testBit a (fromInteger . toInteger $ i)
> :t testBitW
testBitW :: (Bits a, Integral s) => a -> s -> Bool

这是放在源文件中的类型签名。

答案 1 :(得分:2)

第二个代码段不起作用的原因是您没有(... Bits a, Bits b) =>作为约束的一部分。 Integral并不意味着Bits。在这种情况下,您根本不需要转换第一个参数,只需要fromIntegral作为第二个参数(就像您的第一个代码片段一样)。

testBit要求其第一个参数属于Bits的实例类型,并且您无法从Integral约束中确定,因为这两个类型类基本上是独立的彼此。

此外,我怀疑这些fromIntegral次呼叫的运行时间成本最低。

顺便说一下,fromIntegraldefined as

fromIntegral :: (Integral a, Num b) => a -> b
fromIntegral = fromInteger . toInteger

虽然RULESfromIntegral优化了一些常见案例的定义,GHC.Word中的RULES Data.Word更多(fromInteger $ toInteger a) default () {1}})。

我相信代码在GHCi中工作的原因是这部分testBitW默认为更具体的类型。 GHCi比GHC具有更积极的类型默认(特别是对于像这样的数字类型)。如果我使用{{1}}禁用GHCi中的数字默认值,然后尝试在第二个示例中定义{{1}},则看起来它会出现相同的错误。