I have a definition of class
class Functor f => Pointed f where
pure :: a -> f a
And now I would like to make instance for Maybe. Why doesn't this work?
instance Pointed (Maybe s) where
pure Nothing = Nothing
pure (Just a) = a
class Functor f where
fmap :: (a->b) -> f a -> f b
Error is:
Kind mis-match
The first argument of `Pointed' should have kind `* -> *',
but `Maybe s' has kind `*'
In the instance declaration for `Pointed (Maybe s)'
Failed, modules loaded: none.
In the definition of Pointed, f has kind * -> * so you need to provide a type constructor with the same kind. Maybe has that kind, while (Maybe s) has kind *. If you substitute Maybe for f in the definition of pure you get:
pure :: a -> Maybe a
Your definition should therefore look like:
instance Pointed Maybe where
pure a = Just a
The kind * -> * is inferred for f due to the rules for kind inference. a is assumed to have kind * as it is a function parameter (which has kind * -> * -> *). f a should have kind * so f has kind * -> *.
In the definition of Pointed, Functor f => is a class context and declares that Functor is a superclass of Pointed. This means that all instances of Pointed must also be instances of Functor.
Maybe is already an instance of Functor so you don't need to define it yourself.
Related
When type variables are constrained by classes in Haskell, I understand what that means.
For example, in a function declaration,
myFunction :: Foldable f => f a -> b
means that f is a type with an instance of Foldable which wraps some other type a.
But what does it mean when a type variable is constrained by a kind?
Consider for instance this definition for Foldable:
class Foldable (t :: * -> *) where
Also, does the fact that 1 example is from a function definition and the other example is from a class definition make any difference in what the constraint means?
t :: * -> * is not a constraint, it is a kind annotation. In this case, it is used to remark that Foldable can take as arguments type constructors such as Maybe, Identity, [], or even partially applied ones like Either Bool and (,) String. By contrast Foldable Int and Foldable [Bool] would be kind errors.
t :: * -> * can be read as "t maps types to types".
The point is, when we have Foldable f we then use f as in f a, applying f to one argument. If we allow f = Maybe we get Maybe a which makes sense. If we allowed f = Int, we would get Int a which is meaningless.
When having a parametrized type:
data A a=X a| Y
I have tried (successfully) implementing Functor and Applicative without specifiying the type parameter:
instance Functor A where instead of instance Functor (A a) where.Why does it work ? Looking in LYAH it seems all examples specify the type parameter in all their typeclass instances.
When should you neglect the type parameter ?
instance Functor A where instead of instance Functor (A a) where.
Why does it work ?
I find this easier to understand using GHC's kinding system. Let's start from a simple case, and experiment in GHCi:
> :k Eq Int
Eq Int :: Constraint
This tells us that Eq Int is a constraint, some property that might be verified during type checking. Indeed, if we type check (12 :: Int) == (42 :: Int), the compiler will verify that integers can be compared, resolving the constraint Eq Int.
What is Eq alone, the name of the class without the Int parameter?
> :k Eq
Eq :: * -> Constraint
This tells us that Eq can be thought of a function from types (* is the kind of types) to constraint.
Indeed, in Eq Int, Int is a type, so we have Int :: * making Int a well-kinded argument to pass to Eq.
Enough of type classes, what about type constructors?
> :k Maybe Int
Maybe Int :: *
No surprise, Maybe Int is a type
> :k Maybe
Maybe :: * -> *
Maybe instead, is a function from types to types (*->*). This is indeed what the Maybe type constructor does: mapping a type (Int) to a type (Maybe Int).
Back to the original question. Why can't we write instance Functor (A a) but we can instead write instance Functor A? Well, we have that
> :k A Int
A Int :: *
> :k A
A :: * -> *
and, most importantly,
> :k Functor
Functor :: (* -> *) -> Constraint
This tells us the the kind of the Functor type class is not the same kind of the Eq type class. Eq expects a type as an argument, while Functor expects something of kind (* -> *) as an argument. A fits that kind, while A Int does not.
This happens when, in the definition of the class, the argument is applied to some other type. E.g.
class C1 a where
foo :: a -> Bool
results in C1 :: * -> Constraint. Instead,
class C2 f where
bar :: f Int -> Bool
results in C2 :: (* -> *) -> Constraint, since f is not itself used as a type, f Int is, so f must be a parameterized type of kind * -> *.
When should you neglect the type parameter?
The type parameter is not "neglected". Let us first take a look at the Functor type class:
class Functor f where
fmap :: (a -> b) -> f a -> f b
Notice the f a and f b in the type signature. We thus here "construct types" for the type signature of fmap.
Here f is thus basically a function that takes a type and transforms it into a type. For example if f ~ A if a ~ Int, then f a generates the A Int type.
Learn You a Haskell for the Greater Good! actually explains this in its chapter about Functors, Applicatives and Monoids:
Many times, we want to make our types instances of certain type
classes, but the type parameters just don't match up for what we want
to do. It's easy to make Maybe an instance of Functor, because
the Functor type class is defined like this:
class Functor f where
fmap :: (a -> b) -> f a -> f b
So we just start out with:
instance Functor Maybe where
And then implement fmap. All the type parameters add up because the Maybe takes the place of f in
the definition of the Functor type class and so if we look at fmap
like it only worked on Maybe, it ends up behaving like:
fmap :: (a -> b) -> Maybe a -> Maybe b
(...)
If I inspect the kind of Maybe I get this:
λ> :k Maybe
Maybe :: * -> *
Now, if I inspect the kind of Monad I get this:
λ> :k Monad
Monad :: (* -> *) -> Constraint
What is Constraint there and why it is needed ? Why not just this * -> * ?
Unlike Maybe, Monad is not a type; it is a typeclass.
The same goes for other typeclasses:
Num :: * -> Constraint
Functor :: (* -> *) -> Constraint
Bifunctor :: (* -> * -> *) -> Constraint
Where * represents concrete types (such as Bool or Int), -> represent higher-kinded types (such as Maybe), and Constraint represents the idea of a type constraint. This is why:
As we know we can't make a signature like this:
return :: a -> Monad a -- This is nonsense!
Because Monad should be used as a constraint, to say that, 'this must be a monad to work':
return :: (Monad m) => a -> m a
We do this because we know that return can't work on any old type m, so we define the behaviour of return for different types under the name Monad. In other words, there is no single thing that can be called a Monad, but only behaviour that can be called Monadic.
For this reason, we have created this type constraint, saying that we must have pre-defined something as a Monad to use this function. This is why the kind of Monad is (* -> *) -> Constraint - it itself is not a type!
Maybe is an instance of Monad. This means that somewhere, someone has written:
instance Monad Maybe where
(>>=) = ... -- etc
...and defined how Maybe should behave as a Monad. This is why we can use Maybe with functions or types that have the prefix constraint Monad m => .... This is essentially where one defines the constraint applied by Monad.
Constraint is the kind of e.g. Show Int, Monad Maybe, and Monoid [a]. Roughly, it is the kind of everything that can occur on the left side of => in type annotations.
Now since
Show Int :: Constraint
and Int is a type, i.e.
Int :: *
we can assign a functional kind to Show as follows
Show :: * -> Constraint
^-- the result kind
^-- the kind of Int
In your case it just happens that a Monad takes argument like Maybe, so
Maybe Int :: *
Maybe :: * -> *
Monad :: (* -> *) -> Constraint
^-- the result kind
^-- the kind of Maybe
Based on this question, in this code
data Promise a b = Pending (a -> b) | Resolved b | Broken
instance Functor (Promise x) where
fmap f (Pending g) = Pending (f . g)
IF
g :: a -> b
then
Pending g :: Promise a b
also
f :: b -> c
because of the existence of f . g.
That means
Pending (f . g) :: Promise a c`.
Wrapping up
fmap :: (b -> c) -> Promise a b -> Promise a c
Now fmap alone has this signature (adapted to the above)
fmap :: Functor f => (b -> c) -> f b -> f c
This only conforms if you assume that f = Promise a. While the end product seems reasonable, how do you interpret the type of f or equivalently what it the type of a partially applied promise Promise a?
At the type level you have another programming language, almost-Haskell. In particular, you can view types as having constructors and being able to be partially applied.
To view this a bit more rigorously, we introduce "types of types" called "kinds". For instance, the type constructor Int has kind
Int ::: *
where I write (:::) to read "has kind", though this isn't valid Haskell syntax. Now we also have "partially applied type constructors" like
Maybe ::: * -> *
which has a function type just like you'd expect at the value level.
There's one really important concept to the notion of kinds—values may instantiate types only if they are kind *. Or, for example, there exist no values of type Maybe
x :: Maybe
x = -- .... what!
In fact, it's not possible to even express a type of kind other than * anywhere where we'd expect that type to be describing a value.
This leads to a certain kind of restriction in the power of "type level functions" in Haskell in that we can't just universally pass around "unapplied type constructors" since they don't always make much sense. Instead, the whole system is designed such that only sensible types can ever be constructed.
But one place where these "higher kinded types" are allowed to be expressed is in typeclass definitions.
If we enable KindSignatures then we can write the kinds of our types directly. One place this shows up is in class definitions. Here's Show
class Show (a :: *) where
show :: a -> String
...
This is totally natural as the occurrences of the type a in the signatures of the methods of Show are of values.
But of course, as you've noted here, Functor is different. If we write out its kind signature we see why
class Functor (f :: * -> *) where
fmap :: (a -> b) -> f a -> f b
This is a really novel kind of polymorphism, higher-kinded polymorphism, so it takes a minute to get your head all the way around it. What's important to note however is that f only appears in the methods of Functor being applied to some other types a and b. In particular, a class like this would be rejected
class Nope (f :: * -> *) where
nope :: f -> String
because we told the system that f has kind (* -> *) but we used it as though it could instantiate values, as though it were kind *.
Normally, we don't have to use KindSignatures because Haskell can infer the signatures directly. For instance, we could (and in fact do) write
class Functor f where
fmap :: (a -> b) -> f a -> f b
and Haskell infers that the kind of f must be (* -> *) because it appears applied to a and b. Likewise, we can fail "kind checking" in the same was as we fail type checking if we write something inconsistent. For instance
class NopeNope f where
fmap :: f -> f a -> a
implies that f has kind * and (* -> *) which is inconsistent.
You are only missing the equations for Resolved and Broken. The only reasonable implementation I can think of is
fmap f (Resolved x) = Resolved (f x)
fmap _ Broken = Broken
Other than that, your code is fine.
I wanted to add to #J. Abrahamson's fantastic answer. A lot of my understanding from Haskell's kind system is from this diogo castro's blog which I highly recommend.
Coming to the question of Partially Applied Types. Apart from type classes it's also possible to use them in type constructors. Taking an example from the blog.
data NonEmpty f a = MkNonEmpty { head :: a, tail :: f a }
:k NonEmpty
-- NonEmpty :: (* -> *) -> * -> *
:t MkNonEmpty { head = (3 :: Int), tail = Maybe 3 }
-- :: NonEmpty Maybe Int
This is an old question so this might be a recent addition to Haskell. It can be summarized as type constructors can take types and type constructors as arguments.
In Haskell, what does ((->) t) mean in the type signature of instances? For example Functor, Applicative and Monad all have an instance along the lines of:
Functor ((->) r)
I can't find any explanation of what this type signature means and it's highly search engine-resistant.
-> is an infix type constructor. You can compare it with : - an infix value constructor for list type. To use : alone we put parentheses around it so it becomes a prefix function application:
(:) a b is the same as a : b
Similarly, (->) a b is the same as a -> b, type of a function from a to b.
(->) a is a partial application of type constructor, and itself a type constructor of kind * -> *.
You can think of it as "a constructor of types of functions from a". E.g. (->) Int is a constructor of types of functions from Int. You can construct full function type by passing another type to it: (->) Int String is the type of functions from Int to String.
instance Functor (->) a is a functor with fmap operation transforming an a -> b function into an a -> c function. You can compare it with a similar instance Functor (Either a) which maps Either a b to Either a c by applying the fmap argument to Right values.
We could use lambda functions and infix functions:
(->) a = \b -> (->) a b --pseudo-Haskell
(->) a = \b -> a -> b --pseudo-Haskell
so, read instance as:
class Functor f where
fmap :: (a->b) -> f a -> f b
instance Functor ((->)r) where
fmap :: (a->b) -> f a -> f b
= (a->b) -> (->)r a -> (->)r b --pseudo-Haskell
= (a->b) -> (r -> a) -> (r -> b) --pseudo-Haskell
You could see it as the set of types r -> a where r is fixed.
A functor is a type function m, which means that for any type a you have a type m a. Examples are Maybe, [] and (->) r. The latter should perhaps better be written (r ->), but I don't know if that's allowed.