[英]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.