Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(Num a) vs Integer type inference

Tags:

haskell

Consider the following Haskell function:

sign a
  | a < 0 = (-1)
  | a > 0 = 1
  | otherwise = 0

When I load this into ghci I expected :t sign to be:

sign :: (Num a, Ord a) => a -> Integer

Instead it inferred it as:

*Main> :t sign
sign :: (Num a1, Num a, Ord a1) => a1 -> a

Similarly, if I ask for the type of the integer 5, I expected Integer, but instead I got

*Main> :t 5
5 :: Num a => a

There's something I am not understanding about Haskell's types. The thing is, if all I know about the return type of sign is that it is an instance of the Num typeclass, then I should not be able to pass its return value into this function:

double :: Integer -> Integer
double x = x * 2

That is, my double function requires an Integer, not just any instance of Num.

Yet, the following works just fine:

*Main> double (sign 5.5)
2

What is it that I am mis-understanding about Haskell's type system?

like image 432
Paul Hollingsworth Avatar asked Mar 16 '13 10:03

Paul Hollingsworth


People also ask

What is NUM A in Haskell?

Num is a typeclass — a group of types — which includes all types which are regarded as numbers. The (Num a) => part of the signature restricts a to number types – or, in Haskell terminology, instances of Num .

What is Haskell type inference?

Type inference is the process by which Haskell 'guesses' the types for variables and functions, without you needing to specify these types explicitly. Many functional languages feature type inference. There is lots of theory behind type inference — Hindley-Milner type systems and Unification.

What is integer Haskell?

Haskell has two integral types, namely Int and Integer . Int is the type of limited-precision integers; this means that there is a smallest integer of type Int , namely minBound , and a greatest integer of type Int , namely maxBound .

What are types in Haskell?

In Haskell, every statement is considered as a mathematical expression and the category of this expression is called as a Type. You can say that "Type" is the data type of the expression used at compile time.


2 Answers

In Haskell, if a function returns type x is its result, that means that the caller can choose what x should be, not the function. Rather, the function must be able to return any possible type.

Your sign can return any type of data - including Integer. The double function wants an Integer, so that's just fine - sign can return that.

Another part of the puzzle you may not be aware of: In Java, 2 has type int and 2.0 has type double. But in Haskell, 2 has type Num x => x - in other words, any possible number type. (Also 2.0 has type Fractional x => x, which is a similar deal.)

like image 174
MathematicalOrchid Avatar answered Oct 21 '22 14:10

MathematicalOrchid


The thing is, if all I know about the return type of 'sign' is that it is an instance of the Num typeclass, then I should not be able to pass its return value into this function:

Right, if that were all that you knew, you couldn't pass it to double.

But the type

sign :: (Num a1, Num a, Ord a1) => a1 -> a

means that the result type of sign is whichever Num type the caller demands. Type variables in type signatures are (implicitly) universally quantified, not existentially, like for e.g. Java interfaces.

sign can produce a return value of arbitrary type, subject to the restriction it be an instance of Num, and the type it returns is determined by the calling context.

If the caller wants an Integer, it gets one. If it wants a Double, no problem either.

I forgot to mention initially:

Similarly, if I ask for the type of the integer 5, I expected "Integer", but instead I got

    *Main> :t 5
    5 :: Num a => a

Numeric literals are polymorphic, an integer literal stands for fromInteger value, and a fractional literal for fromRational value.

like image 37
Daniel Fischer Avatar answered Oct 21 '22 14:10

Daniel Fischer