Reputation: 1829
What does f a
and f b
tell me about its type?
class Functor f where
fmap :: (a -> b) -> f a -> f b
I think I get the idea behind standard instances of a functor. However I'm having hard time understanding what f a
and f
actually represent.
I understand that f a
and f b
are just types and they must carry information what type constructor was used to create them and type arguments that were used.
Is f
a type constructor of kind * -> *
? Is (->) r
a type constructor just like Maybe
is?
Upvotes: 2
Views: 190
Reputation: 30237
My (possibly mildly tortured) reading of chapter 4 of the Haskell 2010 Report is that Maybe
and (->) r
are both types, of kind * -> *
. Alternatively, the Report also labels them as type expressions—but I can't discern a firm difference in how the Report uses the two terms, except perhaps for surface syntax details. (->)
and Maybe
are type constructors; type expressions are assembled from type constructors and type variables.
For example, section 4.1.1 ("Kinds") of the 2010 report says (my boldface):
To ensure that they are valid, type expressions are classified into different kinds, which take one of two possible forms:
- The symbol ∗ represents the kind of all nullary type constructors.
- If κ1 and κ2 are kinds, then κ1 → κ2 is the kind of types that take a type of kind κ1 and return a type of kind κ2.
Section 4.3.2, "Instance Declarations" (my boldface):
An
instance
declaration that makes the type T to be an instance of class C is called a C-T instance declaration and is subject to these static restrictions:
- A type may not be declared as an instance of a particular class more than once in the program.
- The class and type must have the same kind; this can be determined using kind inference as described in Section 4.6.
So going by that language, the following instance
declaration makes the type (->) r
to be an instance of the class Functor
:
instance Functor ((->) r) where
fmap f g = f . g
The funny thing about this terminology is that we call (->) r
a "type" even though there are no expressions in Haskell that have that type—not even undefined
:
foo :: (->) r
foo = undefined
{-
[1 of 1] Compiling Main ( ../src/scratch.hs, interpreted )
../src/scratch.hs:1:8:
Expecting one more argument to `(->) r'
In the type signature for `foo': foo :: (->) r
-}
But I think that's not a big deal. Basically, all declarations in Haskell must have types of kind *
.
As a side note, from my limited understanding of dependently typed languages, many of these lack Haskell's firm distinction between terms and types, so that something like (->) Boolean
is an expression whose value is a function that takes a type as its argument and produces a type as its result.
Upvotes: 1
Reputation: 672
I understand that f a and f b are just types and they must carry information what type constructor was used to create them and type arguments that were used.
Good explanation.
Is
f
a type constructor of kind* -> *
?
In effect.
Is
(->) r
a type constructor just like Maybe is?
In effect, yes:
Yes in the sense that you can apply it to a type like String
and get r -> String
, just like you can apply Maybe
to String
to get Maybe String
. You can use for f
anything that gives you a type from any other type.
..but no...
No, in the sense that Daniel Wagner points out; To be precise, Maybe
and []
are type constructors, but (->) r
and Either a
are sort of like partially applied type constructors. Nevertheless they make good functors, because you can freely apply functions "inside" them and change the type of "the contents".
(Stuff in inverted commas is very hand-wavy imprecise terminology.)
Upvotes: 2