我写了以下函数。
f :: Integer -> Integer
f x = if (odd x) then 0 else (floor . logBase 2) x
但是会出现以下编译时错误:
F.hs:2:31: No instance for (RealFrac Integer) arising from a use of
floor' Possible fix: add an instance declaration for (RealFrac Integer) In the first argument of
(.)', namely `floor' In the expression: floor . logBase 2 In the expression: (floor . logBase 2) xF.hs:2:39: No instance for (Floating Integer) arising from a use of
logBase' Possible fix: add an instance declaration for (Floating Integer) In the second argument of
(.)', namely `logBase 2' In the expression: floor . logBase 2 In the expression: (floor . logBase 2) x Failed, modules loaded: none.
如何正确编写上述函数?
最佳答案
这会有点长,因为我不仅想为您提供有效的代码,还想深入解释这个问题,以便您更好地理解 GHC 的类型错误。
正如已经简要回答的那样(并且类型错误尽力告诉你,虽然它肯定不够清楚),以便使用 logBase x y
,两个参数x
和 y
必须都是“浮点”类型类的实例。
特别是,logBase
是 Floating
的一种方法类型类(来自 Prelude's documentation ):
class Fractional a => Floating a where Source
logBase :: a -> a -> a
我们还发现,同样来自 Prelude:
class (Real a, Fractional a) => RealFrac a where Source
floor :: Integral b => a -> b
也就是说,为了使用函数
(floor . logBase)
,我们需要两个参数Fractional
(因为 logBase
需要这个)和 Real
(因为 floor
两者都需要)。这两者的合并定义为RealFrac
,而这正是 GHC 提示您未能提供它的原因(在您的函数的类型声明中)。它为什么提示?从 Prelude 我们发现以下
instance
RealFrac
的声明.请注意,“RealFrac Integer
”缺失:RealFrac Double
RealFrac Float
RealFrac CDouble
RealFrac CFloat
Integral a => RealFrac (Ratio a)
HasResolution a => RealFrac (Fixed a)
Haskell 的工作方式是,如果你给它一个整数文字(没有小数点的连续数字),它将假定它属于
Integral
typeclass(并会尝试确定是否将其设为 Integer
或 Int
隐式),但它会 从不将整数文字隐式提升为 Fractional
之一类(包括 RealFrac
)。由于没有“RealFrac Integer
”行,这意味着你不能指望 Haskell 编译你的代码。你告诉 Haskell 你会给它
Integral
通过您的显式类型声明实例(这是为什么这些通常是一个好主意的原因之一 - Haskell 会悄悄地接受您的函数声明,否则只会在使用它的客户端函数中引发编译错误):f :: Integer -> Integer
解决方案是通过使用以下函数来提升您的整数(将
Integral
s 转换为任何兼容的 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
文字)作为基础。
关于haskell - 计算整数 `log` 的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26416323/