By :: a
we mean "Any type", but not a subtype. a
could be Int
, or Bool
, or IO (Maybe Ordering)
, but none in particular. a
is not a type exactly, but a type variable.
Let's say we have a function like this:
id x = x
The compiler understands that there is no specific type for our argument x
. We can use any type for x
, just as long as it's equivalent to whatever comes out of id. So, we write the signature as so:
-- /- Any type in...
-- | /- ...same type out.
-- V V
id :: a -> a
Remember that types begin with a capital letter in Haskell. This is not a type: it is a type variable!
We use polymorphism because it's easier to do so. For instance, composition is a useful idea:
(>>>) :: (a -> b) -> (b -> c) -> (a -> c)
(>>>) f g a = g (f a)
So we can write things like:
plusOneTimesFive :: Int -> Int
plusOneTimesFive = (+1) >>> (* 5)
reverseHead :: [Bool] -> Bool
reverseHead = reverse >>> head
But what if we had to write every type out like this:
(>>>) :: (Bool -> Int) -> (Int -> String) -> (Bool -> String)
(>>>) f g a = g (f a)
(>>>') :: (Ordering -> Double) -> (Double -> IO ()) -> (Ordering -> IO ())
(>>>') f g a = g (f a)
(>>>'') :: (Int -> Int) -> (Int -> Bool) -> (Int -> Bool)
(>>>'') f g a = g (f a)
-- ...and so on.
That'd just be silly.
So the compiler infers the type using type unification like so:
Let's say I input this into GHCi. Let's say 6
in an Int
for simplicity here.
id 6
The compiler thinks: "id :: a -> a
, and it's being passed an Int
, so a = Int
, so id 6 :: Int
.
This is not subtyping. Subtyping could be captured using typeclasses, but this is basic polymorphism at play.
undefined
is not subtyping. It is an error. Why do you think this is subtyping? – Entrancewaymempty :: forall m. Monoid m => m
andlet x = mempty :: [Int]
. – Razorforall a. a
is equivalent to bottom - "bottom is an inhabitant of every type (though with some caveats concerning types of unboxed kind), bottoms can be used wherever a value of that type would be." – RazorMonoid
example is quite different, since what's really happening is that the typeclass instances are passed behind the scenes like a dictionary, so that the type restriction::[Int]
causes a lookup in that dictionary. – Razor[Int]
but you can't write[forall a. a]
(unless you enable impredicativity, which does not work so well with type inference). – Leathaleatherlens
library has a quite impressive "subtyping hierarchy" encoded using forall polymorphism and typeclasses. So whether or not this counts as subtyping, it can certainly be used that way. – Ganister