[英]Haskell cast Integer to Int
為什么第一個是正確的而第二個不是? 我想以第二種方式實現代碼,這樣我就不必每次都從Intete中調用,但我不明白如何...
正確
bits :: Integer -> Int
bits 0 = 0
bits n = fromInteger n `mod` 2 + bits(fromInteger n `div` 2)
不正確
bits :: Integer -> Int
bits 0 = 0
bits n = let m = fromInteger n in m `mod` 2 + bits(m `div` 2)
因為第二次通話你不需要它:
bits :: Integer -> Int
bits 0 = 0
bits n = fromInteger n `mod` 2 + bits (n `div` 2)
第二個fromInteger
再次導致Integer
,由參數強制為bits
。
以下是此版本未進行類型檢查的原因:
bits :: Integer -> Int
bits 0 = 0
bits n = let m = fromInteger n in m `mod` 2 + bits(m `div` 2)
首先,請注意m
的第一次使用要求m
是Int
因為bits
調用的結果必須是Int
,這意味着加法的左側(即m `mod` 2
)必須是Int
。 為什么是這樣? 嗯,這是因為+
運算符的簽名是:
(+) :: (Num a) => a -> a -> a
這要求+
兩個參數與其結果具有相同的類型。 類似地,因為m `mod` 2
必須是Int
,所以`mod`
調用的`mod`
(即m
)必須是Int
,因為mod
有簽名:
mod :: (Integral a) => a -> a -> a
所以,這就是m
的第一次使用需要m :: Int
。 呼!
出於同樣的原因, m
的第二種用法要求m
是Integer
。 這是因為參數bits
在表達式bits (m `div` 2)
必須是一個Integer
,其要求的左手側`div`
操作者必須是一個Integer
。
因此,我們要求m
既是Int
又是Integer
。 這不一定是個問題。 如果你寫了:
bits :: Integer -> Int
bits 0 = 0
bits n = m `mod` 2 + bits(m `div` 2)
where m :: (Integral a) => a
m = fromInteger n
並且給定m
一個顯式的多態類型簽名,那么m
可以同時用作Int
和Integer
。 然而,由於稱為單形態限制的東西,沒有明確的類型簽名, m
需要具有單個非多態(即,單態類型)。 如果添加pragma:
{-# LANGUAGE NoMonomorphismRestriction #-}
到你的文件的頂部,然后原始定義typechecks罰款:
{-# LANGUAGE NoMonomorphismRestriction #-}
bits :: Integer -> Int
bits 0 = 0
bits n = let m = fromInteger n in m `mod` 2 + bits(m `div` 2)
但是其他人已經注意到,你實際上並不需要在兩個地方使用fromInteger
; 並且同時使用Int
和Integer
是不必要的,並且使用具有約束的單個整數類型( Integral a
) 可能更好。
此外,如果您希望此功能用於實際工作而不僅僅是練習,那么它已經在模塊Data.Bits
作為popCount
Data.Bits
。
您可能稍微調整一下簽名並擺脫所有fromInteger
s。
bits :: Integral a => a -> a
bits 0 = 0
bits n = n `mod` 2 + bits (n `div` 2)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.