Here is another way to look at it. Some function arguments are invisible, others are visible. The type input -> output tells us that a visible input is expected as an argument. Type (Constraint) => output tells us that some invisible information is expected. They are not interchangeable because visible arguments must be written, and invisible arguments must not be written. The invisible arguments are that the compiler must understand it (well, it sounds like me), and he insists on puzzling them: he refuses to just say what they are!
In secret, the full type of this tell example is
tell :: forall (a :: *). (Show a) => [a] -> String
What I did was to indicate where this variable a goes and what this thing is. You can also read this as a "deal": tell offers to work for all types of a that satisfy the request (Show a) .
There are three things that make sense to tell . Two of them are invisible, and one of them is visible. That is, when you use tell , you make the visible argument explicit, and the compiler tries to fill in the invisible parts. Let work through this type more slowly.
tell :: forall (a :: *). -- the type of elements to tell (invisible) (Show a) => -- how to make a String from one element (invisible) [a] -> -- the list of elements to be told (visible) String -- the String made by showing all the elements
So, when you use tell , for example,
tell [True, False]
you specify only a visible argument: a list of [True, False] things to tell, and the compiler calculates invisible arguments. He knows that True and False are both values of type Bool , therefore means
[True, False] :: [Bool]
how the compiler determines that a in the type tell must be Bool , making [a] = [Bool]
(By the way, near [True, False] :: [Bool] . On the left side :: square brackets [..], enter the list values. Right :: square brackets, [..], enter the list type. They may just look black on a gray background for you, but my brain colors the colored square brackets in red and the fonts in blue. They are completely different. I'm sorry that I can’t draw the code on this site.
So, now another invisible argument should satisfy this thing (Show a) , which we now know specifically (Show Bool) , because we found out that a is Bool . We call this part of the type “restriction”, but in fact this requirement is not only about the truth of the fact, but also that there is some useful material. The material required here is that there is a function
show :: Bool -> String
This function is used to convert individual True and False elements to String during the tell [True, False] evaluation process.
Show is the name of the type class, and show is the class method of this type. The class type indicates the operation interface that should be implemented for each instance . An invisible argument to a function is a record (or "dictionary") that packs implementations of these operations for the type in question (here is the implementation of Show ). Without this information, the compiled code will not be able to do its job, but we do not need to write this information, because the compiler can (at least in this case) search through instances of which it knows, and fill them out alone for work.
So, we have not just arguments of an invisible type (which are displayed at compile time and then deleted before runtime), they are signaled by variables of the lower case type or more explicitly - forall blah . . We also have invisible implementations of class type operations (which are scanned at compile time to provide vital runtime information). So, something very important happens between type inference and deletion: while the compiler still knows the types, it uses them to find out what invisible implementations are needed at runtime so that we can leave without writing them down ourselves.
The reduction, => in type documents is our expectation that the compiler will use type information to generate runtime code that we do not need to write. This is a good win, right there.
Street motive for type system hackers. The message that the invisible visible difference is in another place from the erased useful difference is that some people have not yet received. This is Hindley-Milner's classic position, but the fact is that these differences are orthogonal, and the sooner people learn to enjoy it, the better.