Reputation:
I was disappointed about fact that it correct typing:
renumberTree2' :: Tree a -> StateT Int Identity (Tree Int)
renumberTree2' t = get >>= (\v -> return (Empty))
After all, we have that:
(>>=) :: m a -> (a -> m b) -> m b
. Due to the fact that StateT s m a
we can't give to bind get :: StateT s m s
. get is not of type m a
as expected bind.
However, get s
where s :: s->(a, s')
is correct type which should be given to bind. Where am I wrong ?
Upvotes: 1
Views: 89
Reputation: 144206
get
has type m s
where s
is the state type. The MonadState
instance for StateT
has context:
Monad m => MonadState s (StateT s m)
so the monad type m
is StateT s m
. Therefore the type of get
for StateT
is:
(StateT s m) s
The function given to (>>=)
must have type s -> StateT s m b
for some result type b
.
return (Empty)
has type StateT s m (Tree Int)
as required since StateT s m
is a monad .
Upvotes: 1
Reputation: 54078
You are mistaken in your reading of the types. You can treat higher kinded types (those with type parameters) much like you would functions with precedence. If you have a function
f :: a -> b -> c -> d -> e
f a b c d = undefined
Then calling it
let e = f a b c d
is equivalent to
let e = (((f a) b) c) d
Since f a :: b -> c -> d -> e
, and so on for (f a) b
, etc.
When you see the type StateT s m a
, you can also read it as ((StateT s) m) a
, the types are equivalent and GHC will happily accept that syntax. In this way it may be easier to see how Monad m => StateT s m a
can be aligned with Monad m' => m' a'
:
m' ~ StateT s m
a' ~ a
This implies that the Monad m'
in question is StateT s m
. A simpler example that works in the exact same way is the Functor
instance for Either a
. It isn't Either
that has a Functor
instance, but Either a
, since a Functor
is a type with kind * -> *
, meaning a type that takes only one type parameter.
Upvotes: 6
Reputation: 64750
After all, we have that:
(>>=) :: m a -> (a -> m b) -> m b
> :type (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
True.
get is not of type
m a
as expected [by] bind.
> import Control.Monad.State
> :type get
get :: MonadState s m => m s
No, get
is of type m a
(though it does carry a constraint).
Upvotes: 2