Higher kinded type on typeclass? [duplicate] - haskell

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

Related

Monad Transformer missing parameter (?)

I've got this type alias:
type Board a = ReaderT String (StateT String IO) a
I know that StateT has the kind * -> (* -> *) -> * -> * so it should get three parameters. But in the above example, StateT only receives String and the IO-Monad.
Now I'm wondering where the missing parameter is passed to StateT.
Same goes for IO which should get one parameter but doesn't get any.
If you look at the definition of ReaderT, you will see that its second parameter is itself applied to its last parameter:
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
^^^
right here
Which means that its second parameter m must have kind m :: * -> *. And this is exactly what you get if you apply only two, not three, parameters to StateT:
StateT :: * -> (* -> *) -> * -> *
StateT x y :: * -> *
(where x :: * and y :: * -> *)
When substituting the definition of ReaderT in your type Board, you'll get:
(1) type Board a = ReaderT String (StateT String IO) a
-- Substituting ReaderT definition (pseudocode)
(2) type Board a = { runReaderT :: String -> StateT String IO a }
^^^^^^^^^^^^^^^^^^
Look, StateT has all its three parameters!
You correctly observe that
StateT has the kind * -> (* -> *) -> * -> *
and the same is true of ReaderT.
So it takes 3 "parameters" as you call them. The first is String, of kind *, and the third is a, again of kind *. While the second must be of kind * -> *.
And that is given in your example by StateT String IO. So although there is in one sense a "missing parameter" of StateT, this needs to be "missing" in order to get something of kind * -> * - if you tried something like type Board a = ReaderT String (StateT String IO Int) a, this would fail with a "kind error", precisely because ReaderT's second type argument needs to be of kind * -> *, not of kind * which StateT String IO Int would have.
The same applies to why IO is used on its own rather than something of the form IO a. StateT String (IO Int) wouldn't work because StateT needs to apply to something of kind * -> * as its second type argument - IO has this kind but IO Int (or anything of the form IO a) does not.
To take a step back, monad transformers like ReaderT and StateT transform another monad, and a monad must always be of kind * -> *. IO is a monad, and so is StateT String IO. But IO Int and StateT String IO Int are not monads - and not for failing the monad laws or anything like that, but for a much more fundamental meaning, they are the wrong kind. (They are "concrete types" - types which have values - rather than "type constructors" that take another type as an argument.)

What Does Kind Constraint mean in Haskell typeclass instance?

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.

Why does parametrized type instance works without specifying type parameter

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
(...)

MaybeT's m in Type Signature

Looking at MaybeT:
λ: import Monad.Trans
λ: import Monad.Trans.Maybe
λ: :t MaybeT
MaybeT :: m (Maybe a) -> MaybeT m a
In MaybeT's signature, can m be any higher-kinded type, i.e. * -> *?
I'm trying to learn Monad Transformers, so I was curious why the m did not have a constraint of Monad.
To quote Learn You A Haskell:
Another example of a parameterized type that we've already met is Map k v from Data.Map. The k is the type of the keys in a map and the v is the type of the values. This is a good example of where type parameters are very useful. Having maps parameterized enables us to have mappings from any type to any other type, as long as the type of the key is part of the Ord type class. If we were defining a mapping type, we could add a type class constraint in the data declaration:
data (Ord k) => Map k v = ...
However, it is a very strong convention in Haskell to never add type class constraints in data declarations. Why? Well, because we don't benefit a lot, but we end up writing more class constraints, even when we don't need them. If we put or don't put the Ord k constraint in the data declaration for Map k v, we're going to have to put the constraint into functions that assume the keys in a map can be ordered. But if we don't put the constraint in the data declaration, we don't have to put (Ord k) => in the type declarations of functions that don't care whether the keys can be ordered or not. An example of such a function is toList, that just takes a mapping and converts it to an associative list. It's type signature is toList :: Map k a -> [(k, a)]. If Map k v had a type constraint in its data declaration, the type for toList would have to be toList :: Ord k => Map k a -> [(k, a)], even though the function doesn't do any comparing of keys by order.
So don't put type constraints into data declarations even if it seems to make sense, because you'll have to put them into the function type declarations either way.
I hope that answers your question. Although the m in MaybeT m a is unconstrained yet there is an implicit assumption that m is an instance of Monad. In fact, if m is not an instance of Monad then you wouldn't be able to do much with a MaybeT m a value because most functions would require that m be an instance of Monad.
In MaybeT's signature, can m be any higher-kinded type, i.e. * -> *?
No:
> :k MaybeT
MaybeT :: (* -> *) -> * -> *
So, the m in the type MaybeT m a must be exactly of kind * -> *, and not of any other kind.
For instance, note the kind error below:
> :k MaybeT (State Int)
MaybeT (State Int) :: * -> *
> :k MaybeT State
Expecting one more argument to ‘State’
The first argument of ‘MaybeT’ should have kind ‘* -> *’,
but ‘State’ has kind ‘* -> * -> *’
In a type in a GHCi command: MaybeT (State)
can m be any higher-kinded type, i.e. * -> *?
It can be anything with kind * -> *. Other than that, there are no restrictions in principle.
why the m did not have a constraint of Monad.
The constraint is provided through the types of the functions that use MaybeT, rather than through the MaybeT constructor. Adding constraints to constructors is not useful unless GADTs are involved (I believe transformers does not use GADTs for the sake of simplicity and compliance to the standard). See this question and its answers for extra commentary on constraints and datatype declarations.

Understanding `kind` of MonadTrans

Looking at the kind of Monad:
ghci>:k Monad
Monad :: (* -> *) -> Constraint
I believe that's because it takes an a from m a, and returns the Monad constraint.
Looking at MonadTrans's *kind, I see:
ghci>:i MonadTrans
class MonadTrans (t :: (* -> *) -> * -> *) where
lift :: Monad m => m a -> t m a
-- Defined in `Control.Monad.Trans.Class'
instance MonadTrans MaybeT
-- Defined in `Control.Monad.Trans.Maybe'
So, the first (* -> *) comes from Monad's kind, I believe. But what about the * -> *?
The second * -> * also comes from Monad's kind! A monad transformer takes a type argument that is a Monad (or at least a type that has the kind of a Monad) and produces a new type which is a Monad (which also has the kind of a Monad).
* -> * -- a Monad
(* -> *) -> * -> * -- Something that takes a Monad and makes a new Monad.
* -> * -- also a Monad

Resources