简体   繁体   中英

No instance for (Floating Integer) arising from a use of '**'?

I have the following Haskell code:

two :: Integer -> Integer
two i = toInteger(2 ** i)

Why isn't it working?

(**) requires floating point input based on the function signature:

(**) :: Floating a => a -> a -> a

toInteger on the other hand requires input that is integral in nature:

toInteger :: Integral a => a -> Integer

Therefore, you cannot reconcile the two the way you use it. That said, since you seem to be expecting integer input anyway, you might consider using (^) instead, like so:

two :: Integer -> Integer
two i = 2 ^ i

As @leftaroundabout correctly points out in the comments, (^) will fail for negative values of i . This can be resolved by checking for value and handling in an alternate manner, something like this:

two :: Integer -> Integer
two i = if i > 0 then 2 ^ i else floor (2 ** fromIntegral i)

Use ^ instead:

two i = 2 ^ i

And then there is no need for to cast the result back to an Integral type.

The reason this...

two :: Integer -> Integer
two i = toInteger(2 ** i)

...doesn't work is because you've declared i to be an integer, and if we look at the type of (**) ...

Prelude> :t (**)
(**) :: Floating a => a -> a -> a

... all it's arguments are of the same type, and that type has to be an instance of the Floating type-class. Integer is not an instance of Floating . This is what "No instance of (Floating Integer)" means.

The simplest solution is to use ^ as ErikR suggests. It raises a number to an integral power.

(^) :: (Integral b, Num a) => a -> b -> a

If you want to work through using ** to learn a bit more, keep reading.


So we need to convert your integer into a type which is an instance of Floating . You can do this with fromIntegral . If we do this:

two :: Integer -> Integer
two i = toInteger(2 ** fromIntegral(i))

...we still get a load of error messages complaining that various types are ambiguous. These aren't as clear as the first message, but the issue is the use of toInteger which becomes apparent if we look at it's type.

Prelude> :t toInteger
toInteger :: Integral a => a -> Integer

As we're passing the result of ** to toInteger , and that is a Floating , not an Integral , toInteger is the wrong function. round is a better choice.

two :: Integer -> Integer
two i = round(2 ** fromIntegral(i))

This now works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM