I just want to clear my doubts on the fromIntegral type in Haskell.
The output for these 2 euclidean distance functions are the same, so what's the point of putting fromIntegral? Like they both give floating point values of the euclidean distances.
Also, for the type definition of my function distance2 which uses the fromIntegral type, why is it (Floating a1, Integral a2) and then => (a2, a2) -> (a2, a2) -> a1? I just don't quite get the interpretation of it here.
distance2 :: (Floating a1, Integral a2) => (a2, a2) -> (a2, a2) -> a1
distance2 (x1, y1) (x2, y2)
= sqrt (fromIntegral ((x2-x1)^2 + (y2 - y1)^2))
distance3 :: Floating a => (a, a) -> (a, a) -> a
distance3 (x1, y1) (x2, y2)
= sqrt ((x2-x1)^2 + (y2 - y1)^2)
Could someone please help with an explanation, thank you:)
The output for these 2 euclidean distance functions are the same, so what's the point of putting fromIntegral? Like they both give floating point values of the euclidean distances.
They both give floating point values, but they don't both take floating point values.
> distance3 (pi, 0) (0, 0)
3.141592653589793
> distance2 (pi, 0) (0, 0)
<interactive>:2:1: error:
• Could not deduce (Integral a20) arising from a use of ‘distance2’
from the context: Floating a1
bound by the inferred type of it :: Floating a1 => a1
<snipped considerable additional error text>
Also, for the type definition of my function distance2 which uses the fromIntegral type, why is it (Floating a1, Integral a2) and then => (a2, a2) -> (a2, a2) -> a1?
Your distance2
function takes numbers, and returns numbers, but not the same type of numbers. The incoming numbers must be integer-like things, so that you can apply fromIntegral
to them; but the outgoing numbers must be floating-point-like things, so that you can apply sqrt
to them. For example, here are some monomorphic types that distance2
can be specialized to:
(Int, Int) -> (Int, Int) -> Double
(Integer, Integer) -> (Integer, Integer) -> Double
(Word, Word) -> (Word, Word) -> Float
This English description is captured by creating two type variables, each with different constraints. An identical type for distance2
, but with somewhat more human-readable variable names, might look like this:
(Floating float, Integral int) => (int, int) -> (int, int) -> float
fromIntegral
is used to convert the value of type Integral a => a
that your sum-of-squares produces into a value of type Floating a => a
that sqrt
expects.
fromIntegral
has type (Integral a, Num b) => a -> b
. That means that, given a value of type Integral a
, it will give you back a value of any type b
that has a Num
instance. Since Floating
has Num
as a superclass (by way of Fractional
), that means fromIntegral
can produce a value of type Floating a => a
.
There are two relevant typeclasses here:
Integral
is the typeclass for types representing a subset of integers
Integral
type has a function toInteger
that converts its values to the arbitrary-length integer type Integer
Num
is the typeclass for numeric types that include integers as a subset
Num
type has a function fromInteger
that converts arbitrary-length Integer
values to values of that Num
typeThe prelude function fromIntegral
is defined as:
fromIntegral = fromInteger . toInteger
It uses both of those functions to convert any Integral
type to any Num
type.
This is what lets your first function take any Integral
type as input: the input type is inferred through the sum-of-squared-differences expression as the input to fromIntegral
, and selects toInteger
from that type's instance of Integral
, while the Floating
output type is inferred through the sqrt
function to demand it as a result from the fromIntegral
call, and selects the fromInteger
from the output type's Num
instance.
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.