這樣會稍微長一些,因爲我想不只是給你一些可行的代碼,而是深入解釋這個問題,這樣你就可以更好地理解GHC的類型錯誤。
前面已經回答簡單(和類型錯誤會盡可能地告訴你,雖然這肯定是不夠清晰),以使用logBase x y
,這兩個參數x
和y
都必須是實例的「浮點「類型類。
尤其logBase
是Floating
類型類的方法(從Prelude's documentation):
class Fractional a => Floating a where Source
logBase :: a -> a -> a
我們還發現,還從前奏:
class (Real a, Fractional a) => RealFrac a where Source
floor :: Integral b => a -> b
也就是說,爲了使用函數(floor . logBase)
,我們需要兩個參數Fractional
(因爲logBase
需要這個)和Real
(因爲floor
需要bo日)。這兩者的合併被定義爲RealFrac
,這正是GHC抱怨你沒有提供它(在你的函數的類型聲明中)。
爲什麼抱怨?從前奏中,我們找到RealFrac
的以下instance
聲明。請注意,「RealFrac Integer
」丟失:
RealFrac Double
RealFrac Float
RealFrac CDouble
RealFrac CFloat
Integral a => RealFrac (Ratio a)
HasResolution a => RealFrac (Fixed a)
方式Haskell的工作,就是如果你給它(不帶小數點連續數字)字面一個整數,就會認爲它屬於Integral
類型類(和將試圖找出是否使其隱含地爲Integer
或Int
),但它將從永不隱含地將整數文字提升爲Fractional
類之一(包括RealFrac
)。由於沒有「RealFrac Integer
」這一行,這意味着你不能期望Haskell編譯你的代碼。
您告訴Haskell您將通過顯式類型聲明爲它提供Integral
實例(這就是爲什麼這些通常是個好主意的原因之一 - Haskell會默默接受您的函數聲明,否則只會拋出編譯在使用它的客戶端功能)錯誤:
f :: Integer -> Integer
的解決方案是通過使用下面的函數(Integral
SIN轉換成任何兼容Num
BER類型),以促進您的整數:
fromIntegral :: (Integral a, Num b) => a -> b
Floor
執行相反方向的轉換(從Fractional
到Integral
),如其類型所示。
總之你需要簡單地說
f :: Integer -> Integer
f x = if (odd x) then 0 else (floor . logBase 2.0 . fromIntegral) x
注意fromIntegral
呼籲,請與編譯器期望是什麼,以及使用2.0
(一Fractional
文字)兼容的參數類型爲基地。
'fromIntegral'是你的朋友。 – luqui 2014-10-17 01:06:58
謝謝,luqui。這特別有用 - http://stackoverflow.com/a/1970515/409976。 – 2014-10-17 01:25:22
'地板。 logBase 2' =>'floor。 logBase 2。 fromIntegral' – user2407038 2014-10-17 01:42:02