haskell - 计算整数 `log` 的函数

标签 haskell

我写了以下函数。

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) x

F.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 ,两个参数xy必须都是“浮点”类型类的实例。

特别是,logBaseFloating 的一种方法类型类(来自 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(并会尝试确定是否将其设为 IntegerInt 隐式),但它会 从不将整数文字隐式提升为 Fractional 之一类(包括 RealFrac )。由于没有“RealFrac Integer”行,这意味着你不能指望 Haskell 编译你的代码。

你告诉 Haskell 你会给它Integral通过您的显式类型声明实例(这是为什么这些通常是一个好主意的原因之一 - Haskell 会悄悄地接受您的函数声明,否则只会在使用它的客户端函数中引发编译错误):
f :: Integer -> Integer

解决方案是通过使用以下函数来提升您的整数(将 Integral s 转换为任何兼容的 Num ber 类型):
fromIntegral :: (Integral a, Num b) => a -> b
Floor执行相反方向的转换(从 FractionalIntegral ),如其类型所示。

总之你需要简单地说
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/

相关文章:

haskell - 列表推导式中的 where 子句

haskell - 为什么内衬会在此构造上窒息?

haskell - 为什么 GHC Sparks 会失败?

haskell - Haskell 中的终端迷宫游戏

haskell - 为什么Float和Double在加上0.1和0.2的情况下会不同?

parsing - 我的 Megaparsec 解析器卡住了,而且 ghci 调试也没有帮助

haskell - GADT 中 De Bruijn 索引变量的等式

oop - 在 Haskell 中扩展数据结构的继承

haskell - Haskell 函数的参数数量

haskell - 如何抑制生成代码中的警告?