Domanda

LYAH describes fromIntegral as:

From its type signature we see that it takes an integral number and turns it into a more general number. That's useful when you want integral and floating point types to work together nicely.

I don't understand how this function works at all or why it is needed from playing around with the interpreter.

fromIntegral 4 + 3.2
7.2
4 + 3.2
7.2 -- seems to work just fine?!
fromIntegral 6
6
fromIntegral 6.2
-- raises an error

:t fromIntegral
fromIntegral :: (Integral a, Num b) => a -> b -- does this mean it takes 1 arg or 2?
È stato utile?

Soluzione

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

takes one arg. The => should be read as a logical implication with universal quantification:

for all types a and b,

if a is an instance of Integral and b is an instance of Num,

then fromIntegral can take an a and produce a b.

This function converts a value of type a (which is an Integral type) to the b type (which is an instance of the more general Num class). E.g. you cannot add the integer 1 to the float 2 in Haskell without converting the former:

Prelude> (1 :: Int) + (2 :: Float)

<interactive>:10:15:
    Couldn't match expected type `Int' with actual type `Float'
    In the second argument of `(+)', namely `(2 :: Float)'
    In the expression: (1 :: Int) + (2 :: Float)
    In an equation for `it': it = (1 :: Int) + (2 :: Float)
Prelude> fromIntegral (1 :: Int) + (2 :: Float)
3.0

Altri suggerimenti

fromIntegral will convert a integral value, such as Int, to a more general value, a.k.a Num a.

For example, (4 :: Int) + 3.2 will not type check, but fromIntegral (4 :: Int) + 3.2 will work just fine.

:t fromIntegral
fromIntegral :: (Integral a, Num b) => a -> b

It means that it takes one parameter of input type a and returns another parameter of type b. The class constraint just indicate that a type has to be instance of Integral typeclass and b type has to be instance of Num typeclass. So fromIntegral actually converts Integer types to a more general one. This is useful in many conversions.

Regarding the use-case of fromIntegral, this example will make that clear:

λ> :t (/)
(/) :: Fractional a => a -> a -> a

λ> let a = 3 :: Int
λ> a / 4.2

<interactive>:62:3:
    No instance for (Fractional Int) arising from a use of `/'
    Possible fix: add an instance declaration for (Fractional Int)
    In the expression: a / 4.2
    In an equation for `it': it = a / 4.2
λ> fromIntegral a / 4.2
0.7142857142857143

Or taking your own example:

λ> let a = 3 :: Int
λ> a + 4.2

<interactive>:5:5:
    No instance for (Fractional Int) arising from the literal `4.2'
    Possible fix: add an instance declaration for (Fractional Int)
    In the second argument of `(+)', namely `4.2'
    In the expression: a + 4.2
    In an equation for `it': it = a + 4.2
λ> fromIntegral a + 4.2
7.2

The constraints on the signature of fromIntegral:

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

means the argument type a must be an instance of the Integral class, while the result type b is any Num instance.

fromIntegral 6.2

fails to type check since 6.2 is not an instance of Integral.

4 + 3.2

works because the type of (+) is Num a => a -> a -> a while the type of 3.2 is Fractional a => a. Since Fractional is a subclass of Num, GHC has inferred the type of Fractional a => a for the expression 4 + 3.2.

does this mean it takes 1 arg or 2?

To answer that, first note that => and -> are different. Then, look just at the part of the signature to the right of the =>:

a -> b

A function with such a type would have just one argument, and so does fromIntegral. To the left => you do not find arguments, but type constraints. If the type of fromIntegral was a -> b then it would take an argument of any type and produce a result of any other type. The (Integral a, Num b) constraint restricts the types, so that the type of argument has to be an instance of the Integral class (that is, the argument has to be an integral number) and the result has to be an instance of Num (that is, the result has to be some kind of number).

You need fromIntegral whenever you have an integral number and need to use it with a function that expects a non-integral numeric argument. A simple example would be adding an Integer to a Double. But then, how come does the following work without fromIntegral?

Prelude> 4 + 3.2
7.2

The answer lies in the literals:

Prelude> :t 4
4 :: Num a => a

4 is not an Int or an Integer, but a polymorphic Num value. When placed in a complex expression, it gets a type appropriate to its surroundings. Given:

Prelude> :t 3.2
3.2 :: Fractional a => a
Prelude> :t (+)
(+) :: Num a => a -> a -> a

The 4 in 4 + 3.2 becomes subject to the Fractional constraint of 3.2, and so:

Prelude> :t 4 + 3.2
4 + 3.2 :: Fractional a => a

If there are no further constraints anywhere else in a program, a polymorphic Fractional value will default to Double. A brief explanation of such defaulting is given by the answer to this question.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top