Return specific type within Haskell - haskell

I have a pretty general question about Haskell's type system. I'm trying to become familiar with it, and I have the following function:
getN :: Num a => a
getN = 5.0 :: Double
When I try to compile this, I get the following error:
Couldn't match expected type `a' against inferred type `Double'
`a' is a rigid type variable bound by
the type signature for `getN' at Perlin.hs:15:12
In the expression: 5.0 :: Double
In the definition of `getN': getN = 5.0 :: Double
As I understand this, the function is set up to "return" a type in the class Num. Double is in this class (http://www.zvon.org/other/haskell/Outputprelude/Num_c.html), so I would have expected that it would be okay to "return" a Double in this case.
Can someone explain this please?

A function with signature Num a => a is expected to work for any type in the class Num. The implementation 5.0 :: Double just works for one type, not for all types of the class, so the compiler complains.
An example of a generic function would be:
square :: (Num a) => a -> a
square x = x * x
This works for any type that is a Num. It works for doubles, integers and whatever other numbers you want to use. Because of that it can have a generic type signature that just requires the parameter to be in class Num. (Type class Num is necessary because the function uses multiplication with *, which is defined there)

To add to sth's answer: Haskell is not object-oriented. It's not true that Double is a subclass of Num, so you cannot return a Double if you promise to return a polymorphic Num value, like you can in, say, Java.
When you write getN :: Num a => a you promise to return a value that is fully polymorphic within the Num constraint. Effectively this means that you can only use functions from the Num type class, such as +, *, - and fromInteger.

Check out Existentially quantified types.
One way to solve it would be to define a new data type
data NumBox = forall n. Num n => NumBox n
You'll need -XExistentialQuantification to get this to work.
Now you can write something like
getN :: NumBox
getN = NumBox (5.0 :: Double)
You can also define a NumBox-list as
let n3 = [NumBox (4.0 :: Double), NumBox (1 :: Integer), NumBox (1 :: Int) ]

Related

Confusion with Haskell classes

I am confused with classes in Haskell as follows.
I can define a function that takes an Integral argument, and successfully supply it with a Num argument:
gi :: Integral a => a -> a
gi i = i
gin = gi (3 :: Num a => a)
I can define a function that takes a Num argument, and successfully supply it with an Integral argument:
fn :: Num a => a -> a
fn n = n
fni = fn (3 :: Integral a => a)
I can define an Integral value and assign a Num to it
i :: Integral a => a
i = (3 :: Num a => a)
But if I try to define a Num value, then I get a parse error if I assign an Integral value to it
- this doesn't work
n :: Num a => a
n = (3 :: Integral a => a)
Maybe I am being confused by my OO background. But why do function variables appear to let you go 'both ways' i.e. can provide a value of a subclass when a superclass is 'expected' and can provide a value of a superclass when a subclass is expected, whereas in value assignment you can provide a superclass to a subclass value but can't assign a subclass to a superclass value?
For comparison, in OO programming you can typically assign a child value to a parent type, but not vice-versa. In Haskell, the opposite appears to be the case in the second pair of examples.
The first two examples don't actually have anything to do with the relationship between Num and Integral.
Take a look at the type of gin and fni. Let's do it together:
> :t gin
gin :: Integer
> :t fni
fni :: Integer
What's going on? This is called "type defaulting".
Technically speaking, any numeric literal like 3 or 5 or 42 in Haskell has type Num a => a. So if you wanted it to just be an integer number dammit, you'd have to always write 42 :: Integer instead of just 42. This is mighty inconvenient.
So to work around that, Haskell has certain rules that in certain special cases prescribe concrete types to be substituted when the type comes out generic. And in case of both Num and Integral the default type is Integer.
So when the compiler sees 3, and it's used as a parameter for gi, the compiler defaults to Integer. That's it. Your additional constraint of Num a has no further effect, because Integer is, in fact, already an instance of Num.
With the last two examples, on the other hand, the difference is that you explicitly specified the type signature. You didn't just leave it to the compiler to decide, no! You specifically said that n :: Num a => a. So the compiler can't decide that n :: Integer anymore. It has to be generic.
And since it's generic, and constrained to be Num, an Integral type doesn't work, because, as you have correctly noted, Num is not a subclass of Integral.
You can verify this by giving fni a type signature:
-- no longer works
fni :: Num a => a
fni = fn (3 :: Integral a => a)
Wait, but shouldn't n still work? After all, in OO this would work just fine. Take C#:
class Num {}
class Integral : Num {}
class Integer : Integral {}
Num a = (Integer)3
// ^ this is valid (modulo pseudocode), because `Integer` is a subclass of `Num`
Ah, but this is not a generic type! In the above example, a is a value of a concrete type Num, whereas in your Haskell code a is itself a type, but constrained to be Num. This is more like a C# interface than a C# class.
And generic types (whether in Haskell or not) actually work the other way around! Take a value like this:
x :: a
x = ...
What this type signature says is that "Whoever has a need of x, come and take it! But first name a type a. Then the value x will be of that type. Whichever type you name, that's what x will be"
Or, in plainer terms, it's the caller of a function (or consumer of a value) that chooses generic types, not the implementer.
And so, if you say that n :: Num a => a, it means that value n must be able to "morph" into any type a whatsoever, as long as that type has a Num instance. Whoever will use n in their computation - that person will choose what a is. You, the implementer of n, don't get to choose that.
And since you don't get to choose what a is, you don't get to narrow it down to be not just any Num, but an Integral. Because, you know, there are some Nums that are not Integrals, and so what are you going to do if whoever uses n chooses one of those non-Integral types to be a?
In case of i this works fine, because every Integral must also be Num, and so whatever the consumer of i chooses for a, you know for sure that it's going to be Num.

Setting type of fractional to num

Could someone please explain why this compiles
Prelude> 1 :: Num a => a
and this doesn't
Prelude> 1.0 :: Num a => a
Second example would work with Fractional, but Num is superclass of Fractional. Just like it's superclass of Integral.
If we have
x :: Num a => a
the user of x can pick a as wanted. E.g.
x :: Int
What would this evaluate to if x = 1.5 ?
For this reason a floating point literal can't be given the polytype Num a => a, since its value won't (in general) fit all Numeric types.
Integral literals instead fit every numeric type, so they are allowed.
The superclass relationship between type classes does not establish relationships between types. It tells us only that if type t is a member of type class C, and B is a super class of C, then t will also be member of B.
It doesn't say that each value v::t can be used at any type that is also member of B. But this is what you are stating with:
3.14159 :: Num a => a
It's important to distinguish between polymorphism in OO languages and polymorphism in Haskell. OO polymorphism is covariant, while Haskell's parametric polymorphism is contravariant.
What this means is: in an OO language, if you have
class A {...}
class B: A {...}
i.e. A is a superclass of B, then any value of type B is also a value of type A. (Note that any particular value is actually not polymorphic but has a concrete type!) Thus, if you had
class Num {...}
class Fractional: Num {...}
then a Fractional value could indeed be used as a Num value. That's roughly what covariant means: any subclass value is also a superclass value; the values hierarchy goes the same direction as the type hierarchy.
In Haskell, classes are different. There is no such thing as a “value of type Num”, only values of concrete types a. That type may be in the Num class.
Unlike in OO languages, a value like 1 :: Num a => a is polymorphic: it can take on whatever type the environment demands, provided the type is in the Num class. (Actually that syntax is just shorthand for 1 :: ∀ a . Num a => a, to be read as “for all types a, you can have a value 1 of type a.) For example,
Prelude> let x = 1 :: Num a => a
Prelude> x :: Int
1
Prelude> x :: Double
1.0
You can also give x a more specific constraint of Fractional, since that's a subclass of Num. That just restricts what type the polymorphic value can be instantiated to:
Prelude> let x = 1 :: Fractional a => a
Prelude> x :: Int
<interactive>:6:1:
No instance for (Fractional Int) arising from a use of ‘x’
...
Prelude> x :: Double
1.0
because Int is not a fractional type.
Thus, Haskell's polymorphism is contravariant: polymorphic values restricted to a superclass can also be restricted to a subclass instead, but not the other way around. In particular, you can obviously have
Prelude> let y = 1.0 :: Fractional a => a
(y is the same as x'), but you can not generalise this to y' = 1.0 :: Num a => a. Which is a good thing as Ingo remarked since otherwise it would be possible to do
Prelude> 3.14159 :: Int
????

How can a instance with Num type class coercion to Fractional implicitly?

I tested the numeric coercion by using GHCI:
>> let c = 1 :: Integer
>> 1 / 2
0.5
>> c / 2
<interactive>:15:1: error:
• No instance for (Fractional Integer) arising from a use of ‘/’
• In the expression: c / 2
In an equation for ‘it’: it = c / 2
>> :t (/)
(/) :: Fractional a => a -> a -> a -- (/) needs Fractional type
>> (fromInteger c) / 2
0.5
>>:t fromInteger
fromInteger :: Num a => Integer -> a -- Just convert the Integer to Num not to Fractional
I can use fromInteger function to convert a Integer type to Num (fromInteger has the type fromInteger :: Num a => Integer -> a), but I cannot understand that how can the type Num be converted to Fractional implicitly?
I know that if an instance has type Fractional it must have type Num (class Num a => Fractional a where), but does it necessary that if an instance has type Num it can be used as an instance with Fractional type?
#mnoronha Thanks for your detailed reply. There is only one question confuse me. I know the reason that type a cannot be used in function (/) is that type a is with type Integer which is not an instance of type class Fractional (the function (/) requires that the type of arguments must be instance of Fractional). What I don't understand is that even by calling fromInteger to convert the type integer to atype which be an instance of Num, it does not mean a type be an instance of Fractional (because Fractional type class is more constrained than Num type class, so a type may not implement some functions required by Fractional type class). If a type does not fully fit the condition Fractional type class requires, how can it be use in the function (/) which asks the arguments type be instance of Fractional. Sorry for not native speaker and really thanks for your patience!
I tested that if a type only fits the parent type class, it cannot be used in a function which requires more constrained type class.
{-# LANGUAGE OverloadedStrings #-}
module Main where
class ParentAPI a where
printPar :: int -> a -> String
class (ParentAPI a) => SubAPI a where
printSub :: a -> String
data ParentDT = ParentDT Int
instance ParentAPI ParentDT where
printPar i p = "par"
testF :: (SubAPI a) => a -> String
testF a = printSub a
main = do
let m = testF $ ParentDT 10000
return ()
====
test-typeclass.hs:19:11: error:
• No instance for (SubAPI ParentDT) arising from a use of ‘testF’
• In the expression: testF $ ParentDT 10000
In an equation for ‘m’: m = testF $ ParentDT 10000
In the expression:
do { let m = testF $ ParentDT 10000;
return () }
I have found a doc explaining the numeric overloading ambiguity very clearly and may help others with the same confusion.
https://www.haskell.org/tutorial/numbers.html
First, note that both Fractional and Num are not types, but type classes. You can read more about them in the documentation or elsewhere, but the basic idea is that they define behaviors for types. Num is the most inclusive numeric typeclass, defining behaviors functions like (+), negate, which are common to pretty much all "numeric types." Fractional is a more constrained type class that describes "fractional numbers, supporting real division."
If we look at the type class definition for Fractional, we see that it is actually defined as a subclass of Num. That is, for a type a to be an have an instance Fractional, it must first be a member of the typeclass Num:
class Num a => Fractional a where
Let's consider some type that is constrained by Fractional. We know it implements the basic behaviors common to all members of Num. However, we can't expect it to implement behaviors from other type classes unless multiple constraints are specified (ex. (Num a, Ord a) => a. Take, for example, the function div :: Integral a => a -> a -> a (integral division). If we try to apply the function with an argument that is constrained by the typeclass Fractional (ex. 1.2 :: Fractional t => t), we encounter an error. Type classes restrict the sort of values a function deals with, allowing us to write more specific and useful functions for types that share behaviors.
Now let's look at the more general typeclass, Num. If we have a type variable a that is only constrained by Num a => a, we know that it will implement the (few) basic behaviors included in the Num type class definition, but we'd need more context to know more. What does this mean practically? We know from our Fractional class declaration that functions defined in the Fractional type class are applied to Num types. However, these Num types are a subset of all possible Num types.
The importance of all this, ultimately, has to do with the ground types (where type class constraints are most commonly seen in functions). a represents a type, with the notation Num a => a telling us that a is a type that includes an instance of the type class Num. a could be any of the types that include the instance (ex. Int, Natural). Thus, if we give a value a general type Num a => a, we know it can implement functions for every type where there is a type class defined. For example:
ghci>> let a = 3 :: (Num a => a)
ghci>> a / 2
1.5
Whereas if we'd defined a as a specific type or in terms of a more constrained type class, we would have not been able to expect the same results:
ghci>> let a = 3 :: Integral a => a
ghci>> a / 2
-- Error: ambiguous type variable
or
ghci>> let a = 3 :: Integer
ghci>> a / 2
-- Error: No instance for (Fractional Integer) arising from a use of ‘/’
(Edit responding to followup question)
This is definitely not the most concrete explanation, so readers feel free to suggest something more rigorous.
Suppose we have a function a that is just a type class constrained version of the id function:
a :: Num a => a -> a
a = id
Let's look at type signatures for some applications of the function:
ghci>> :t (a 3)
(a 3) :: Num a => a
ghci>> :t (a 3.2)
(a 3.2) :: Fractional a => a
While our function had the general type signature, as a result of its application the the type of the application is more restricted.
Now, let's look at the function fromIntegral :: (Num b, Integral a) => a -> b. Here, the return type is the general Num b, and this will be true regardless of input. I think the best way to think of this difference is in terms of precision. fromIntegral takes a more constrained type and makes it less constrained, so we know we'll always expect the result will be constrained by the type class from the signature. However, if we give an input constraint, the actual input could be more restricted than the constraint and the resulting type would reflect that.
The reason why this works comes down to the way universal quantification works. To help explain this I am going to add in explicit forall to the type signatures (which you can do yourself if you enable -XExplicitForAll or any other forall related extension), but if you just removed them (forall a. ... becomes just ...), everything will work fine.
The thing to remember is that when a function involves a type constrained by a typeclass, then what that means is that you can input/output ANY type within that typeclass, so it's actually better to have a less constrained typeclass.
So:
fromInteger :: forall a. Num a => Integer -> a
fromInteger 5 :: forall a. Num a => a
Means that you have a value that is of EVERY Num type. So not only can you use it in a function taking it in a Fractional, you could use it in a function that only takes in MyWeirdTypeclass a => ... as long as there is one single type that implements both Num and MyWeirdTypeclass. Hence why you can get the following just fine:
fromInteger 5 / 2 :: forall a. Fractional a => a
Now of course once you decide to divide by 2, it now wants the output type to be Fractional, and thus 5 and 2 will be interpreted as some Fractional type, so we won't run into issues where we try to divide Int values, as trying to make the above have type Int will fail to type check.
This is really powerful and awesome, but very much unfamiliar, as generally other languages either don't support this, or only support it for input arguments (e.g print in most languages can take in any printable type).
Now you may be curious when the whole superclass / subclass stuff comes into play, so when you are defining a function that takes in something of type Num a => a, then because a user can pass in ANY Num type, you are correct that in this situation you cannot use functions defined on some subclass of Num, only things that work on ALL Num values, like *:
double :: forall a. Num a => a -> a
double n = n * 2 -- in here `n` really has type `exists a. Num a => a`
So the following does not type check, and it wouldn't type check in any language, because you don't know that the argument is a Fractional.
halve :: Num a => a -> a
halve n = n / 2 -- in here `n` really has type `exists a. Num a => a`
What we have up above with fromInteger 5 / 2 is more equivalent to the following, higher rank function, note that the forall within parenthesis is required, and you need to use -XRankNTypes:
halve :: forall b. Fractional b => (forall a. Num a => a) -> b
halve n = n / 2 -- in here `n` has type `forall a. Num a => a`
Since this time you are taking in EVERY Num type (just like the fromInteger 5 you were dealing with before), not just ANY Num type. Now the downside of this function (and one reason why no one wants it) is that you really do have to pass in something of EVERY Num type:
halve (2 :: Int) -- does not work
halve (3 :: Integer) -- does not work
halve (1 :: Double) -- does not work
halve (4 :: Num a => a) -- works!
halve (fromInteger 5) -- also works!
I hope that clears things up a little. All you need for the fromInteger 5 / 2 to work is that there exists ONE single type that is both a Num and a Fractional, or in other words just a Fractional, since Fractional implies Num. Type defaulting doesn't help much with clearing up this confusion, as what you may not realize is that GHC is just arbitrarily picking Double, it could have picked any Fractional.

How fromIntegral or read works

The fromIntegral returns a Num data type. But it seems that Num is able to coerce to Double or Integer with no issue. Similarly, the read function is able to return whatever that is required to fit its type signature. How does this works? And if I do need to make a similar function, how do I do it?
The type checker is able to infer not only the types of function arguments but also the return type. Actually there is no special case there. If you store the result of fromIntegral or read in Integer, the version for this type will get called. You can create your own function in the same way.
For example:
class Foo a where
foo :: a
instance Foo Integer where
foo = 7
instance Foo String where
foo = "Hello"
x :: Integer
x = 3
main = do
putStrLn foo
print (foo + x)
Because putStrLn has type String -> IO () the type checker finds that the type of foo in putStrLn foo must be String for the program to compile. The type of foo is Foo a => a. So it deduces that a == String and searches for Foo String instance. Such instance exists and it causes thefoo :: Foo String => String value to be selected there.
Similar reasoning happens in print (foo + x). x is known to be Integer, and because the type of (+) is Num a => a -> a -> a the type checker deduces that the left argument of the addition operator must also be Integer so it searches for Foo Integer instance and substitutes the Integer variant.
There is no direction from function arguments to (possible) return type like in C++. The type checker may even deduce function arguments based on knowledge of what the function is expected to return. Another example:
twice :: a -> [a]
twice a = [a,a]
y :: [Integer]
y = twice foo
The function argument here is of type Foo a => a which is not enough to decide which foo to use. But because the result is already known to be [Integer] the type checker finds that it has to provide value of type Integer to twice and does so by using the appropriate instance of foo.
read is a member of a typeclass which means that its implementation can depend on a type parameter.
Also, numeric literals like 1, 42, etc. are syntatic sugar for function calls fromInteger 1, fromInteger 42, etc., and fromInteger itself is a member of the Num typeclass.
Thus, the literal 42 (or fromInteger 42) can return an Int or Double or any other Num instance depending on the context in which it is called.
I'm being a little particular about terminology here, because I think the words you're using betray some misunderstandings about how Haskell works.
The fromIntegral returns a Num data type.
More precisely, fromIntegral takes as input any type that has an instance of class Integral, and can return any type that is an instance of class Num. The prelude defines it like this:
fromIntegral :: (Integral a, Num b) => a -> b
fromIntegral = fromInteger . toInteger
Types with an Integral instance implement thetoInteger function, and all types with a Num instance implement fromInteger. fromIntegral uses the toInteger associated with the Integral a instance to turn a value of type a into an Integer. Then it uses the fromInteger from the Num b instance to convert that Integer into a value of type b.
But it seems that Num is able to coerce to Double or Integer with no issue.
Every time a haskell function is used, it is "expanded". Its definition is substituted for the function call, and the parameters used are substituted into the definition. Each time it is expanded in a different context, it can have different types in its type variables. So each time a function is expanded, it takes certain concrete types and returns a certain concrete type. It doesn't return a typeless thing that gets coerced at some later time.
Similarly, the read function is able to return whatever that is required to fit its type signature.
read :: Read a => String -> a
read takes a String as input, and can be used in any context that returns values of a type for which an instance of class Read exists. When it is expanded during execution of a program, this type is known. It uses the particular definitions in the Read a instance to parse the string into the correct type.

Polymorphic signature for non-polymorphic function: why not?

As an example, consider the trivial function
f :: (Integral b) => a -> b
f x = 3 :: Int
GHC complains that it cannot deduce (b ~ Int). The definition matches the signature in the sense that it returns something that is Integral (namely an Int). Why would/should GHC force me to use a more specific type signature?
Thanks
Type variables in Haskell are universally quantified, so Integral b => b doesn't just mean some Integral type, it means any Integral type. In other words, the caller gets to pick which concrete types should be used. Therefore, it is obviously a type error for the function to always return an Int when the type signature says I should be able to choose any Integral type, e.g. Integer or Word64.
There are extensions which allow you to use existentially quantified type variables, but they are more cumbersome to work with, since they require a wrapper type (in order to store the type class dictionary). Most of the time, it is best to avoid them. But if you did want to use existential types, it would look something like this:
{-# LANGUAGE ExistentialQuantification #-}
data SomeIntegral = forall a. Integral a => SomeIntegral a
f :: a -> SomeIntegral
f x = SomeIntegral (3 :: Int)
Code using this function would then have to be polymorphic enough to work with any Integral type. We also have to pattern match using case instead of let to keep GHC's brain from exploding.
> case f True of SomeIntegral x -> toInteger x
3
> :t toInteger
toInteger :: Integral a => a -> Integer
In the above example, you can think of x as having the type exists b. Integral b => b, i.e. some unknown Integral type.
The most general type of your function is
f :: a -> Int
With a type annotation, you can only demand that you want a more specific type, for example
f :: Bool -> Int
but you cannot declare a less specific type.
The Haskell type system does not allow you to make promises that are not warranted by your code.
As others have said, in Haskell if a function returns a result of type x, that means that the caller gets to decide what the actual type is. Not the function itself. In other words, the function must be able to return any possible type matching the signature.
This is different to most OOP languages, where a signature like this would mean that the function gets to choose what it returns. Apparently this confuses a few people...

Resources