函数来计算Integer的`log` [英] Function to Calculate `log` of Integer

查看:161
本文介绍了函数来计算Integer的`log`的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了下面的函数。

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

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 Integrals into any compatible Number 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆