函数来计算Integer的`log` [英] Function to Calculate `log` of Integer
问题描述
f :: Integer - >整数
fx = if(odd x)then 0 else(floor。logBase 2)x
但是会发生下面的编译时错误:
lockquote
$ F $ s $ 2 $ 31
(RealFrac Integer)由于使用 floor'
(。)'的第一个参数中,即楼层
引起的可能修复:为(RealFrac Integer)
添加一个实例声明在
在表达式:floor中。 logBase 2
在表达式中:(floor。logBase 2)x
F.hs:2:39:
没有实例(浮点整型)由于使用 logBase'
(。)'的第二个参数中, ,即`logBase 2'
可能的修正:为(浮动整数)
添加实例声明在
在表达式:floor中。 logBase 2
在表达式中:(floor。logBase 2)x失败,已加载模块:无。
正确地写上面的函数?
这会有点长,因为我想不只是给你代码可行,但深入解释了这个问题,所以你可以更好地理解GHC的类型错误。
正如已经简要回答的那样最好告诉你,尽管它肯定不够清楚),为了使用 logBase xy
,两个参数 x
和 y
都必须是浮点型类型类的实例。特别是, logBase
是 Floating
> typeclass(来自前奏的文档): p>
class Fractional a =>浮动其中源
logBase :: a - > a - > a
我们也从前奏曲中找到:
class(Real a,Fractional a)=> RealFrac a来源
floor :: Integral b => a - > b
即为了使用函数(floor.logBase)
,我们需要两个参数小数
(因为 logBase
需要这个), Real
(因为 floor
需要两者)。这两者的合并被定义为 RealFrac
,这正是GHC抱怨你没有提供它(在你的函数的类型声明中)。
为什么抱怨?从Prelude开始,我们为 RealFrac
找到以下实例
声明。请注意,缺少 RealFrac Integer
:
RealFrac Double
RealFrac Float
RealFrac CDouble
RealFrac CFloat
Integral a => RealFrac(Ratio a)
HasResolution a => RealFrac(固定a)
Haskell的工作方式是,如果给它一个整数字面值没有小数点的数字),它会假定它属于 Integral
typeclass(并且会试图找出是否使它成为 Integer
或 Int
隐式地),但它会永不 隐式地将整数文字提升为小数
类(包括 RealFrac
)。由于没有 RealFrac Integer
这一行,这意味着你不能期望Haskell编译你的代码。
<你告诉Haskell你将通过你的显式类型声明给它
Integral
实例(这就是为什么这些通常是个好主意的原因之一 - Haskell会有的静静地接受你的函数声明,否则只会在使用它的客户端函数中抛出编译错误):$ b $ pre $ f $ Integer - >整数
解决方法是使用以下函数来提升整数(将 Integral
s到任何兼容的 Num
ber类型中):
fromIntegral ::(Integral a,Num b)=> a - > b
楼层执行相反的转换方向(从小数
到积分
),如其类型所示。
总结,你只需简单地说:
f :: Integer - >整数
fx = if(odd x)then 0 else(floor。logBase 2.0。fromIntegral)x
注意 fromIntegral
调用使参数的类型与编译器所期望的一致,以及使用 2.0
(a 分数
文字)。
I wrote the following function.
f :: Integer -> Integer
f x = if (odd x) then 0 else (floor . logBase 2) x
But the following compile-time error occurs:
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.
How can I properly write the above function?
This will be a tad long, as I would like to not just give you code that works, but explain the issue in depth so you can understand GHC's type errors better.
As already answered briefly (and as the type error tries its best to tell you, although it is certainly not clear enough), in order to use logBase x y
, the two parameters x
and y
must both be instances of the "floating point" typeclasses.
In particular, logBase
is a method of the Floating
typeclass (from the Prelude's documentation):
class Fractional a => Floating a where Source
logBase :: a -> a -> a
We also find, also from the Prelude:
class (Real a, Fractional a) => RealFrac a where Source
floor :: Integral b => a -> b
That is, in order to use the function (floor . logBase)
, we need two parameters which are Fractional
(since logBase
requires this), and Real
(since floor
requires both). The merger of these two is defined as RealFrac
, and that's exactly what GHC is complaining you failed to provide it (in your function's type declaration).
Why is it complaining? From the Prelude we find the following instance
declarations for RealFrac
. Note that "RealFrac Integer
" is missing:
RealFrac Double
RealFrac Float
RealFrac CDouble
RealFrac CFloat
Integral a => RealFrac (Ratio a)
HasResolution a => RealFrac (Fixed a)
The way Haskell works, is that if you give it an integer literal (consecutive digits without a decimal point), it will assume that it belongs to the Integral
typeclass (and will try to figure out whether to make it an Integer
or Int
implicitly), but it will never implicitly promote an integer literal to one of the Fractional
classes (including RealFrac
). Since there is no "RealFrac Integer
" line, this means that you can't expect Haskell to compile your code.
You are telling Haskell that you will give it Integral
instances by your explicit type declaration (this is one of the reasons why these are generally a good idea -- Haskell would have quietly accepted your function declaration otherwise, only to throw compilation errors in the client functions that use it):
f :: Integer -> Integer
The solution is to promote your integers by using the following function (which converts Integral
s into any compatible Num
ber types):
fromIntegral :: (Integral a, Num b) => a -> b
Floor
performs the conversion in the opposite direction (from Fractional
to Integral
), as shown by its type.
In conclusion you need to simply say
f :: Integer -> Integer
f x = if (odd x) then 0 else (floor . logBase 2.0 . fromIntegral) x
Note the fromIntegral
call to make the type of the parameter compatible with what the compiler expects, as well as the use of 2.0
(a Fractional
literal) for the base.
这篇关于函数来计算Integer的`log`的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!