简体   繁体   English

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

[英]How to use Haskell's bitwise functions on unsigned types (e.g., `Word8`, `Word16`)?

What (if anything) can I do in order to be able to use functions from Data.Bits (eg, clearBit , setBit ) on unsigned types, namely Word8 and Word16 ? 为了能够对无符号类型(即Word8Word16 )使用Data.Bits函数(例如, clearBitsetBit ),我该怎么做? At the moment, I get the following error: 此刻,我收到以下错误:

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

I'm going to be performing a large volume of these operations so fromIntegral is not ideal. 我将要执行大量此类操作,因此fromIntegral并不理想。

Any suggestions? 有什么建议么?

Update 2: This is what I needed: 更新2:这是我需要的:

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

Update: 更新:

Am pulling my hair out trying to get the following to compile. 我正在拔头发,试图汇编以下内容。 It's puzzling that the same code works fine if entered directly into GHCi (running :t gives the same implied type signature as per my definition below). 令人费解的是,如果直接输入GHCi,则相同的代码可以正常工作(运行:t给出的隐式类型签名与下面的定义相同)。

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

I keep getting the following two errors. 我不断收到以下两个错误。 Using fromIntegral in place of fromInteger $ toInteger results in the same errors... 使用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.

Importing Data.Word will bring instances of Bits Word8 etc. into scope. 导入Data.Word会将Bits Word8等的实例纳入范围。

Although from your error it looks like you're talking about the second argument to eg setBit , which is specified to be Int . 尽管从您的错误看来,您似乎正在谈论setBit的第二个参数,该参数指定为Int If you want to specify the bit offset with Word s, you'll have to use fromInteger . toInteger 如果要使用Word指定位偏移,则必须使用fromInteger . toInteger fromInteger . toInteger . fromInteger . toInteger You can probably abstract it out somehow, depending on the context. 您可以根据上下文以某种方式抽象出来。

Update 更新资料

The errors of the form "could not deduce..." are, in this case, strong hints from the compiler about the needed type signature. 在这种情况下,“无法推断...”形式的错误是编译器强烈提示的有关所需类型签名的信息。 Here's how to work it out. 这是解决问题的方法。

First, what's the type of testBit ? 首先, testBit的类型是testBit

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

So we know the second argument needs to be an Int (not an Integer !), but the first argument can be any type with a Bits instance. 因此我们知道第二个参数需要是一个Int (而不是Integer !),但是第一个参数可以是具有Bits实例的任何类型。 The most general conversion to an Int is via Integer : 最通用的Int转换是通过Integer

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

Therefore we need to know one thing about each parameter to our testBitW function: the first needs to be an instance of Bits , and the second an instance of Integral . 因此,我们需要了解我们testBitW函数的每个参数的一件事:第一个需要是Bits的实例,第二个需要Integral的实例。 (We don't need to convert the first parameter to an Int , and in fact doing so is almost certainly an error.) (我们并不需要的第一个参数转换为Int ,而事实上这样做几乎可以肯定是一个错误。)

When in doubt, we can let the compiler infer the constraints, which will usually give you the most general type signature: 如有疑问,我们可以让编译器推断约束,这通常会为您提供最通用的类​​型签名:

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

And that's the type signature to put in your source file. 这就是要放在源文件中的类型签名。

The reason that the second code snippet doesn't work is that you don't have (... Bits a, Bits b) => as part of the constraint. 第二个代码段不起作用的原因是,您没有(... Bits a, Bits b) =>作为约束的一部分。 Integral doesn't imply Bits . Integral并不意味着Bits In that case, you also don't need to convert the first argument at all and you just need fromIntegral for the second argument (like your first code snippet). 在这种情况下,您也根本不需要转换第一个参数,而只需要fromIntegral作为第二个参数(例如您的第一个代码段)。

testBit requires its first argument to be of a type that is an instance of Bits , and you can't determine that from Integral constraints since those two type classes are essentially independent of each other. testBit要求其第一个参数的类型为Bits的实例,并且您不能从Integral约束中确定这一点,因为这两个类型类实质上是彼此独立的。

Also, I suspect those fromIntegral calls will have minimal run time cost. 另外,我怀疑fromIntegral调用中的那些将具有最小的运行时成本。

Incidentally, fromIntegral is defined as : 顺便说一下, fromIntegral 定义为

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

Although, there are RULES that optimize that definition out some common cases and there are more fromIntegral RULES for these particular cases in GHC.Word (which is imported by Data.Word ). 虽然,有RULES ,以优化该定义了一些常见的情况和有更多fromIntegral RULES ,在这些特殊情况下GHC.Word (其由导入的Data.Word )。

I believe the reason that the code works in GHCi is this part (fromInteger $ toInteger a) defaulted to a more specific type. 我相信代码在GHCi中起作用的原因是这部分(fromInteger $ toInteger a)默认为更特定的类型。 GHCi has more aggressive type defaulting than GHC (especially for numeric types like these). GHCi比GHC具有更积极的类型默认设置(尤其是对于此类数字类型)。 If I disable the numeric defaulting in GHCi with default () and then try to define testBitW as you have it in the second example, it looks like it gives the same error. 如果我在GHCi中使用default ()禁用了数字默认default () ,然后尝试按照第二个示例中的定义定义testBitW ,看起来它给出了相同的错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM