Instance inductivity as constraint - haskell

I'm trying to express an idea that given
instance (MonadTrans t, MonadX m) => MonadX (t m)
it should follow, that any t1 (t2 ... (tn m)) is also MonadX as long as all tx have MonadTrans instance. However when i try to write it down it doesn't work:
{-# LANGUAGE BasicallyEverything #-}
data Dict c where
Dict :: c => Dict c
class (forall m . Monad m => Monad (t m)) => MonadTrans t where
lift :: Monad m => m a -> t m a
class (c m, Monad m, forall t . (MonadTrans t, Monad (t m)) => c (t m)) => Foo c m
instance (c m, Monad m, forall t . (MonadTrans t, Monad (t m)) => c (t m)) => Foo c m
liftDict :: MonadTrans t => Dict (Foo c m) -> Dict (Foo c (t m))
liftDict Dict = Dict
This results in following error:
• Could not deduce: c (t1 (t m)) arising from a use of ‘Dict’
from the context: MonadTrans t
bound by the type signature for:
liftDict :: forall (t :: (* -> *) -> * -> *)
(c :: (* -> *) -> Constraint) (m :: * -> *).
MonadTrans t =>
Dict (Foo c m) -> Dict (Foo c (t m))
at src/Lib.hs:85:1-64
or from: Foo c m
bound by a pattern with constructor:
Dict :: forall (a :: Constraint). a => Dict a,
in an equation for ‘liftDict’
at src/Lib.hs:86:10-13
or from: (MonadTrans t1, Monad (t1 (t m)))
bound by a quantified context at src/Lib.hs:1:1
• In the expression: Dict
In an equation for ‘liftDict’: liftDict Dict = Dict
• Relevant bindings include
liftDict :: Dict (Foo c m) -> Dict (Foo c (t m))
(bound at src/Lib.hs:86:1)
|
86 | liftDict Dict = Dict
Is there any way to make it work?

You get the exact same error with the slightly simpler definition of Foo c m given here:
(c m, Monad m, forall t. MonadTrans t => c (t m))
^^^ don't really need Monad (t m) here
Let's clarify some of the variable names, so that it's clear which variables are definitely equal and which aren't when writing liftDict.
Have:
MonadTrans t
forall m'. Monad m' => Monad (t m')
Foo c m
c m
Monad m
forall t'. MonadTrans t' => c (t' m)
Want:
Foo c (t m)
c (t m)
Monad (t m)
forall t''. MonadTrans t'' => c (t'' (t m))
In the "want" category, c (t m) is easy -- we apply forall t'. MonadTrans t' => c (t' m) to our t'~t and MonadTrans t. The Monad (t m) is easy, too, by applying forall m'. Monad m' => Monad (t m') to m'~m and Monad m.
But that last one... is tricky! You want these to line up:
Have: forall t' . MonadTrans t' => c (t' m )
Want: forall t''. MonadTrans t'' => c (t'' (t m))
But they don't quite line up. What's happened here is that m is a fixed monad, not an argument that we can specialize to our new choice of t m! Okay, so let's make it an argument.
class (c m, Monad m, forall m' t . (Monad m', MonadTrans t) => c (t m')) => Foo c m
instance (c m, Monad m, forall m' t . (Monad m', MonadTrans t) => c (t m')) => Foo c m
This compiles! But it no longer says what we wanted, because the inductive step we've said here doesn't demand a c constraint. Luckily, we can add that back in without causing it to stop compiling:
class (c m, Monad m, forall m' t . (c m', Monad m', MonadTrans t) => c (t m')) => Foo c m
instance (c m, Monad m, forall m' t . (c m', Monad m', MonadTrans t) => c (t m')) => Foo c m
I think you might find it intuitive to group these constraints slightly differently:
class ( (c m, Monad m) -- base case
, forall m' t. (c m', Monad m', MonadTrans t) => c (t m')
-- inductive hypothesis
) => Foo c m
But beware: this Foo probably has fewer instances than you think at first. In particular, for there to be a Foo c instance, there can be only one, fully general, instance of c for type-level applications.

Related

Typeclass constraints with higher kinded types

I'm trying to write an Eq instance for an EitherT newtype given by:
newtype EitherT e m a = EitherT { runEitherT :: m (Either e a) }
I assumed the following Eq instance would work:
instance (Eq e, Eq a, Eq m) => Eq (EitherT e m a) where
a == b = (runEitherT a) == (runEitherT b)
However, I'm seeing an error:
Expected kind '* -> *', but 'm' has kind '*'
What I'm reading from that error is that my typeclass constraint ( ... Eq m) => ... is confusing the compiler into thinking that I believe m to be of kind *, when my newtype declaration for EitherT expects it to be of kind * -> *.
I'm wondering what I need to do, to declare that I want an Eq instance for some higher kinded type m to implement Eq for my EitherT newtype.
Edit: As pointed out by #AlexisKing, I can get this to work with:
{-# LANGUAGE UndecideableInstances #-}
instance (Eq (m (Either e a))) => Eq (EitherT e m a) where
a == b = (runEitherT a) == (runEitherT b)
However, it seems strange to me to that a language extension is required to write this Eq instance. Is there no other way to express such a typeclass constraint in vanilla Haskell? If not, why?
You're looking for Eq1 which is in Data.Functor.Classes since base 4.9.0.0. Before that it was in one of the -extras packages or transformers? (it's in transformers now since 0.4.0.0)
Eq1 f says that you can compare fs as long as you have a way to compare their contents
class Eq1 f where
liftEq :: (a -> b -> Bool) -> f a -> f b -> Bool
In your case you'd use it like
instance (Eq e, Eq1 m) => Eq1 (EitherT e m) where
liftEq f a b = liftEq (liftEq f) (runEitherT a) (runEitherT b)
The liftEq f is to use the existing Eq1 instance for Either.
And can define an Eq instance as
instance (Eq e, Eq a, Eq1 m) => Eq (EitherT e m a) where
(==) = liftEq (==)
The old Eq1 was
class Eq1 f where
eq1 :: (Eq a) => f a -> f a -> Bool
In your case you'd use it like
instance (Eq e, Eq1 m) => Eq1 (EitherT e m) where
eq1 a b = eq1 (runEitherT a) (runEitherT b)
instance (Eq e, Eq a, Eq1 m) => Eq1 (EitherT e m) where
a == b = eq1 (runEitherT a) (runEitherT b)
It might be worth noting that this instance already exists in current versions of the either package (though not the old EitherT package, which is considered obsolete):
instance Eq (m (Either e a)) => Eq (EitherT e m a) where
(==) = (==) on runEitherT
Of course, as #Alexis King has noted, it requires UndecidableInstances, but the either package is authored by Edward Kmett, a notorious dilettante and amateur who can't write proper Haskell98 like us real programmers. ;)

Resolving overlap of instances with type families

I have a class
class Monad m => MyClass m where
type MyType1 m
type MyType2 m
...
a :: m (MyType1 m)
b :: m (MyType2 m)
c :: m (MyType3 m)
...
and I also have bunch of instances that implement the functions (a ... ) reasonably
instance MyClass A where
type MyType1 A = Int
...
a = ...
...
instance MyClass (B a) where
type MyType1 (B a) = Char
...
a = ...
...
...
but I also have a lot of instances that don't do anything useful apart from lifting the implementation through transformers:
instance MyClass m => MyClass (MyTransA m)
type MyType1 (MyTransA m) = MyType1 m
...
a = lift a
...
instance MyClass m => MyClass (MyTransB m)
type MyType1 (MyTransB m) = MyType1 m
...
a = lift a
...
...
and this turns out to be a lot of boilerplate to write, so I wanted to replace these repetitive uninteresting instances with simply
class MonadTrans t => AutoLiftMyClass t
instance (AutoLiftMyClass a, MyClass m) => MyClass (a m)
type MyType1 (a m) = MyType1 m
...
a = lift a
...
which would allow me to write only
instance AutoLiftMyClass MyTransA
instance AutoLiftMyClass MyTransB
...
to get the lifting for free, avoiding the enumeration of all the lifted a, b, ... for every MyTransA, MyTransB, ...
The problem is that for whatever reason (I really don't know why) GHC considers only the RHS of instance declarations, thus my AutoLiftMyClass collides on type family instances for MyType1, ... with all the reasonable instances A, B, ... (those that don't declare an instance of AutoLiftMyClass)
I have seen some posts and articles on wiki about closed type families but they do not make much sense to me. Is there any way how to make this idea work?
You could use DefaultSignatures, which is supposed to solve exactly this problem:
class Monad m => MyClass m where
type MyType m :: *
type MyType m = MyTypeDef m
val :: m (MyType m)
default val :: (MyClassDef m) => m (MyTypeDef m)
val = defVal
The variants of MyClass, MyType are just a copy of the above, essentially:
class MyClassDef m where
type MyTypeDef m :: *
defVal :: m (MyTypeDef m)
instance
(MonadTrans t, Monad n, MyClass n
) => MyClassDef (t (n :: * -> *)) where
type MyTypeDef (t n) = MyType n
defVal = lift val
Note that an instance is only really needed to cleanly pattern match on the t n constructor. Overlap isn't an issue, because this will only be used in default signatures.
Then your instances are simply:
instance (MyClass m) => MyClass (ReaderT r m)
instance (MyClass m, Monoid r) => MyClass (WriterT r m)
instance (MyClass m) => MyClass (StateT r m)
Of course it may be desirable to have multiple options for a default implementation, but this isn't much harder than the above - you simply add another type to the class:
class MyClassDef (ix :: Symbol) m where
type MyTypeDef ix m :: *
defVal :: m (MyTypeDef ix m)
instance
(MonadTrans t, Monad n, MyClass n
) => MyClassDef "Monad Transformer" (t (n :: * -> *)) where
type MyTypeDef "Monad Transformer" (t n) = MyType n
defVal = lift val
Note that ix is ambiguous in defVal, but I'll use TypeApplications to get around it. You can accomplish the same with Proxy.
The additional parameter is determined when you write the instance, and assuming you don't use overlapping instances (which you shouldn't if you want good type inference, esp. if you want type inference to work with other mtl-style libraries) you can just add it as an associated type:
class Monad m => MyClass m where
type UseDef m :: Symbol
type MyType m :: *
type MyType m = MyTypeDef (UseDef m) m
val :: m (MyType m)
default val :: (MyClassDef (UseDef m) m) => m (MyTypeDef (UseDef m) m)
val = defVal #(UseDef m)
If you forget to implement UseDef, you will get an error like:
* Could not deduce (MyClassDef (UseDef (StateT r m)) (StateT r m))
arising from a use of `Main.$dmval'
but you can provide your own custom error for a missing default if you want:
instance (TypeError (Text ("No default selected"))) => MyClassDef "" m
class Monad m => MyClass m where
type UseDef m :: Symbol
type UseDef m = ""
and if you implement all the methods and types, you get no error, as UseDef isn't used anywhere - only in an instantiated default signature, which won't even exist if the implementation is given.
Your instances incur the cost of an additional line of boilerplate, but it isn't much (esp. with copy-paste):
instance (MyClass m) => MyClass (ReaderT r m) where
type UseDef (ReaderT r m) = "Monad Transformer"
instance (MyClass m, Monoid r) => MyClass (WriterT r m) where
type UseDef (WriterT r m) = "Monad Transformer"
instance (MyClass m) => MyClass (StateT r m) where
type UseDef (StateT r m) = "Monad Transformer"
Note that you do have to supply the required contexts for each instance.
Note that all this is really necessary if you only care about avoiding overlapping instances. If you don't, then use the simple solution and just write
instance {-# OVERLAPS #-} (AutoLiftMyClass a, MyClass m) => MyClass (a m)
or turn on OverlappingInstances.

Having difficulty understanding type inference in Haskell

In Haskell, we know that if we have some function f with the type signature f :: a -> a, then Haskell can infer the following types:
f "alpha" will have type [Char];
f 1234 will have type Num a => a
f Just will have type a -> Maybe a
and so on.
With reference to the following code,
in the function result_sm :: (Monad m) => a -> State m s a, I would like the type variable m to be inferred to State s. State s is an instance of the Monad typeclass, so why isn't it working?
Also, regarding the instance declaration for Functor (StateM m s), I know that the compiler cannot deduce Monad m from the context Functor m bound by the ghc-inbuilt (natural/un-overridden) type signature for fmap.
Similarly, regarding the instance declaration for Applicative (StateM m s), I know that the compiler also cannot deduce Monad m from the context (Functor (StateM m s), Applicative m) bound by the ghc-inbuilt (natural/un-overridden) type signatures for pure and <*>.
So my second question is as follows: how can I get the compiler to accept m as an instance of Monad typeclass in the above two instance declarations, and any similar instance declarations?
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE InstanceSigs #-}
module StateParser where
import Control.Monad
import Control.Applicative
newtype State s a = State {compute :: s -> (a, s)}
newtype StateM m s a = StateM {compute_M :: s -> m (a, s)}
result_s :: a -> State s a
result_s v = State (\s -> (v ,s))
bind_s :: State s a -> (a -> State s b) -> State s b
bind_s st f = State $ \s -> (\(v, s') -> compute (f v) s') (compute st s)
result_sm :: (Monad m) => a -> StateM m s a
result_sm v = StateM (\s -> result_s (v, s))
bind_sm :: (Monad m) => StateM m s a -> (a -> StateM m s b) -> StateM m s b
bind_sm stm f = StateM $ \s -> (tmp s >>= id)
where
tmp s = fmap (\(v, s') -> compute_M (f v) s') (compute_M stm s)
instance Functor (State s) where
fmap f st = st >>= (pure . f)
instance Applicative (State s) where
pure = result_s
p <*> q = p >>= \f ->
q >>= (pure . f)
instance Monad (State s) where
--Explicit return definition only required for code required to be compatible
--with GHC versions prior to 7.10. The default implementation for all GHC
--versions from 7.10 is
return = pure
(>>=) = bind_s
instance Functor m => Functor (StateM m s) where
fmap :: (Monad m) => (a -> b) -> StateM m s a -> StateM m s b
fmap f stm = stm `bind_sm` (result_sm . f)
instance Applicative m => Applicative (StateM m s) where
pure :: (Monad m) => a -> StateM m s a
pure = result_sm
(<*>) :: (Monad m) => StateM m s (a -> b) -> StateM m s a -> StateM m s b
p <*> q = p `bind_sm` \f ->
q `bind_sm` (pure . f)
instance Monad m => Monad (StateM m s) where
return = pure
(>>=) = bind_sm
And here are the full compiler error messages. Someone (username: Bergi) wanted to see them.
StateParser.hs:29:29:
Couldn't match type `m' with `State s0'
`m' is a rigid type variable bound by
the type signature for result_sm :: Monad m => a -> StateM m s a
at StateParser.hs:28:14
Expected type: m (a, s)
Actual type: State s0 (a, s)
Relevant bindings include
result_sm :: a -> StateM m s a (bound at StateParser.hs:29:1)
In the expression: result_s (v, s)
In the first argument of `StateM', namely
`(\ s -> result_s (v, s))'
StateParser.hs:52:11:
Could not deduce (Monad m)
from the context (Functor m)
bound by the type signature for
fmap :: Functor m => (a -> b) -> StateM m s a -> StateM m s b
at StateParser.hs:52:11-63
Possible fix:
add (Monad m) to the context of
the type signature for
fmap :: Functor m => (a -> b) -> StateM m s a -> StateM m s b
When checking that:
forall (m :: * -> *) s.
Functor m =>
forall a b. Monad m => (a -> b) -> StateM m s a -> StateM m s b
is more polymorphic than:
forall (m :: * -> *) s.
Functor m =>
forall a b. (a -> b) -> StateM m s a -> StateM m s b
When checking that instance signature for `fmap'
is more general than its signature in the class
Instance sig: forall (m :: * -> *) s.
Functor m =>
forall a b. Monad m => (a -> b) -> StateM m s a -> StateM m s b
Class sig: forall (m :: * -> *) s.
Functor m =>
forall a b. (a -> b) -> StateM m s a -> StateM m s b
In the instance declaration for `Functor (StateM m s)'
StateParser.hs:56:11:
Could not deduce (Monad m)
from the context (Functor (StateM m s), Applicative m)
bound by the type signature for
pure :: (Functor (StateM m s), Applicative m) => a -> StateM m s a
at StateParser.hs:56:11-40
Possible fix:
add (Monad m) to the context of
the type signature for
pure :: (Functor (StateM m s), Applicative m) => a -> StateM m s a
When checking that:
forall (m :: * -> *) s.
(Functor (StateM m s), Applicative m) =>
forall a. Monad m => a -> StateM m s a
is more polymorphic than:
forall (m :: * -> *) s.
(Functor (StateM m s), Applicative m) =>
forall a. a -> StateM m s a
When checking that instance signature for `pure'
is more general than its signature in the class
Instance sig: forall (m :: * -> *) s.
(Functor (StateM m s), Applicative m) =>
forall a. Monad m => a -> StateM m s a
Class sig: forall (m :: * -> *) s.
(Functor (StateM m s), Applicative m) =>
forall a. a -> StateM m s a
In the instance declaration for `Applicative (StateM m s)'
StateParser.hs:59:12:
Could not deduce (Monad m)
from the context (Functor (StateM m s), Applicative m)
bound by the type signature for
(<*>) :: (Functor (StateM m s), Applicative m) =>
StateM m s (a -> b) -> StateM m s a -> StateM m s b
at StateParser.hs:59:12-75
Possible fix:
add (Monad m) to the context of
the type signature for
(<*>) :: (Functor (StateM m s), Applicative m) =>
StateM m s (a -> b) -> StateM m s a -> StateM m s b
When checking that:
forall (m :: * -> *) s.
(Functor (StateM m s), Applicative m) =>
forall a b.
Monad m =>
StateM m s (a -> b) -> StateM m s a -> StateM m s b
is more polymorphic than:
forall (m :: * -> *) s.
(Functor (StateM m s), Applicative m) =>
forall a b. StateM m s (a -> b) -> StateM m s a -> StateM m s b
When checking that instance signature for `<*>'
is more general than its signature in the class
Instance sig: forall (m :: * -> *) s.
(Functor (StateM m s), Applicative m) =>
forall a b.
Monad m =>
StateM m s (a -> b) -> StateM m s a -> StateM m s b
Class sig: forall (m :: * -> *) s.
(Functor (StateM m s), Applicative m) =>
forall a b. StateM m s (a -> b) -> StateM m s a -> StateM m s b
In the instance declaration for `Applicative (StateM m s)'
The compiler did its job. Your code doesn't make sense.
In result_sm, you are trying to construct a StateM m s a with a State s a, which is a type mismatch. What you probably meant to do was
result_sm :: (Monad m) => a -> StateM m s a
result_sm v = StateM (\s -> return (v, s))
Since bind_sm has the constraint Monad m on it, you need to carry that constraint wherever you use bind_sm, including in the Functor, Applicative, and Monad instances of bind_sm. Therefore, these should read
instance Monad m => Functor (StateM m s) where ..
instance Monad m => Applicative (StateM m s) where ..
instance Monad m => Monad (StateM m s) where ..

define type as Monad

I'm trying to run the code from:
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.39.8039&rep=rep1&type=pdf
using ghci 7.6.3
{-# LANGUAGE LiberalTypeSynonyms, TypeSynonymInstances #-}
type C m a = (a -> Action m) -> Action m
data Action m = Atom (m (Action m)) | Fork (Action m) (Action m) | Stop
This original form:
instance (Monad m) => Monad (C m) where
f >>= k = \c -> f (\a -> k a c)
return x = \c -> c x
gives this error:
Type synonym `C' should have 2 arguments, but has been given 1
In the instance declaration for `Monad (C m)'
Trying with the additional argument:
instance (Monad m) => Monad (C m b) where
f >>= k = \c -> f (\a -> k a c)
return x = \c -> c x
shows this error:
Kind mis-match
The first argument of `Monad' should have kind `* -> *',
but `C m b' has kind `*'
In the instance declaration for `Monad (C m b)'
How to correct this definition? Thanks
Partially applied type synonyms can't be type class instances, and the only way to avoid that in this case is to make this a data or newtype declaration.
You will have to change the definition of C to make this work to e.g.
newtype C m a = C ((a -> Action m) -> Action m)

Why does `hoist` constrain the type parameter of this monad?

I have some function that composes two monads:
comp :: Monad m => m a -> m b -> m b
And two instances of such monads, where on is "inside" an Mfunctor,
ms :: Monad m => m String
ms = undefined
tma :: (Monad m, MFunctor t) => t m a
tma = undefined
Now if I try to compose ms with tma:
tmas = hoist (\ma -> comp ma ms) tma
I am getting this error:
Could not deduce (a ~ [Char])
from the context (Monad m, MFunctor t)
bound by the inferred type of
comp :: (Monad m, MFunctor t) => t m b
at Coroutine.hs:607:1-40
`a' is a rigid type variable bound by
a type expected by the context: m a -> m a at Coroutine.hs:607:8
Expected type: m a
Actual type: m String
which states that a in ms has to be of arbitrary type: ms :: Monad m => m a.
Why is this and is there a way to compose tma with monads of specific parameters.
I can see that signature of hoist is:
hoist :: (Monad m, MFunctor t) => (forall a. m a -> n a) -> t m b -> t n b
but cannot picture how forall is affecting what I am trying to do, if it has any effect.
Switch the order of arguments to comp like this:
tmas = hoist (\ma -> comp ms ma) tma
-- or more simply:
tmas = hoist (comp ms) tma
The reason is that the type of comp is:
comp :: (Monad m) => m a -> m b -> m b
If you set, ms as the second argument, the b type-checks as a String and you get:
(`comp` ms) :: (Monad m) => m a -> m String
... but if you set ms as the first argument, the a type-checks as a String you get:
(ms `comp`) :: (Monad m) => m b -> m b
That latter type is the correct type for hoist since the b is universally quantified (i.e. "forall"ed).
To answer your question about correctness, the answer is that the universal quantification guarantees that the argument to hoist only modifies the monad layer and not the monad return value. However, if it's your intention to modify the return value, too, then hoist is not what you want.
The type of hoist says that it expects a function (forall a. m a -> n a) i.e. a function that changes the "container" type but keeps the type parameter the same. The forall here means that the function you provide cannot be specialized for any specific a but has to work for any type parameter.
The function you are trying to use (\ma -> comp ma ms) has the type m a -> m String so it is pretty much the opposite of what hoist expects since it keeps the container (m) the same but changes the type parameter (from a to String).
I think what you are actually looking for instead of hoist in this case is a function that lifts a monadic function to work on transformed monads, so instead of MFunctor you'll want something like:
import Control.Monad.Trans.Class
tmas :: (Monad m, Monad (t m), MonadTrans t) => t m String
tmas = transLift (\ma -> comp ma ms) tma
transLift :: (Monad m, Monad (t m), MonadTrans t) => (m a -> m b) -> t m a -> t m b
transLift f tma = tma >>= lift . f . return

Resources