[英]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
? 为了能够对无符号类型(即
Word8
和Word16
)使用Data.Bits
函数(例如, clearBit
, setBit
),我该怎么做? 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. 您可以根据上下文以某种方式抽象出来。
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.