Let's look at these functions' types for example:
:t traverse
traverse
:: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)
:t id
id :: a -> a
They have no concrete types, but have generic type parameters:
a, f, b, t (correct me if they called not generic type parameters please)
If I combine id and traverse together in this way,
:t traverse id [Just 1, Just 2, Nothing]
traverse id [Just 1, Just 2, Nothing] :: Num b => Maybe [b]
Haskell can now bind some concrete types for the type variables a, f, b, t.
t = []
a = Maybe bb
f = Maybe
b = Num bb => bb
Below I infer the types and mappings to parameters by hand, is there any way or tool in Haskell to do this automatically, so that it takes some composed parts (id and traverse) in an example, extracts their type signatures in general, and on output produces a mapping from generic type parameters names to concrete inferred types?
See also the first example here: https://wiki.haskell.org/Type_inference
for expression "map ord" on how Haskell finds bindings of actual types to names.
So when we look at functions separately we only have names a, f, b, t. But then we combine the functions and provide some extra information like [Just 1, Just 2, Nothing], and the names a, f, b, t are mapped to concrete types.
I want to catch and show this mapping automatically.
I think
fandtare more generic type constructor parameters, as they act on a type to give you a type (they kind is* -> *, where*means "a concrete type").traverse idis not composition, it is function application, as you are passingidas an argument totraverse.this . thatis function composition betweenthisandthat, in the mathematical sense, where you create a function that gives its (first) argument as an input tothatand feeds the result of this application tothis.You refer to the example in this page, where given this
the compiler is able to deduce that the type of
map ordis[Char] -> [Int], as you can check yourself by writing:t map ordat the command line.If you expect a similar output with concerete types when you type
:t traverse id, you won't get it, for the simple reason thattraverse idis still a polymorphic function, both in its concrete type arguments and type constructor arguments.Just to give a slightly different example, if you type
:t traverse (:[]), where(:[])has typea -> [a], which is a particular case of the(Applicative f) => a -> f bthattraverseexpects, you get this output,which, compared with
:t traverse,tells you that
traverse, intraverse (:[]), has been "instantiated" withf === []anda === b.