[英]How to use Haskell's bitwise functions on unsigned types (e.g., `Word8`, `Word16`)?
为了能够对无符号类型(即Word8
和Word16
)使用Data.Bits
函数(例如, clearBit
, setBit
),我该怎么做? 此刻,我收到以下错误:
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.
导入Data.Word
会将Bits Word8
等的实例纳入范围。
尽管从您的错误看来,您似乎正在谈论setBit
的第二个参数,该参数指定为Int
。 如果要使用Word
指定位偏移,则必须使用fromInteger . toInteger
fromInteger . toInteger
。 您可以根据上下文以某种方式抽象出来。
在这种情况下,“无法推断...”形式的错误是编译器强烈提示的有关所需类型签名的信息。 这是解决问题的方法。
首先, testBit
的类型是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
这就是要放在源文件中的类型签名。
第二个代码段不起作用的原因是,您没有(... Bits a, Bits b) =>
作为约束的一部分。 Integral
并不意味着Bits
。 在这种情况下,您也根本不需要转换第一个参数,而只需要fromIntegral
作为第二个参数(例如您的第一个代码段)。
testBit
要求其第一个参数的类型为Bits
的实例,并且您不能从Integral
约束中确定这一点,因为这两个类型类实质上是彼此独立的。
另外,我怀疑fromIntegral
调用中的那些将具有最小的运行时成本。
顺便说一下, fromIntegral
定义为 :
fromIntegral :: (Integral a, Num b) => a -> b
fromIntegral = fromInteger . toInteger
虽然,有RULES
,以优化该定义了一些常见的情况和有更多fromIntegral
RULES
,在这些特殊情况下GHC.Word
(其由导入的Data.Word
)。
我相信代码在GHCi中起作用的原因是这部分(fromInteger $ toInteger a)
默认为更特定的类型。 GHCi比GHC具有更积极的类型默认设置(尤其是对于此类数字类型)。 如果我在GHCi中使用default ()
禁用了数字默认default ()
,然后尝试按照第二个示例中的定义定义testBitW
,看起来它给出了相同的错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.