A lot of constraints seem to come together. Let's abstract these away.
type MonadNumState a m = (MonadState a m, Num a)
MonadNumState is just a constraint synonym, so I get the benefit of functional dependencies at every use, and can easily throw a MonadNumState a m into a context. Now, suppose I wish to abstract this into a constraint family:
class Iterator t where
type MonadIter t a m :: Constraint
next :: (MonadIter t a m) => m t
...
instance Iterator Foo where
type MonadIter Foo a m = (MonadState a m, Num a)
...
instance Iterator Bar where
type MonadIter Bar a m = (MonadRandom m, MonadSplit a m, RandomGen a)
...
But now a is not a functional dependency. next is virtually unusable since a cannot be inferred. What can I do? Well, I could, of course, use a type family instead. MonadState is written using fundeps, but it should be easy to convert the fundeps to type families.
instance (MonadState s m) => MonadStateFamily m where
type St m = s
get' = get
...
instance (MonadStateFamily m) => MonadState (St m) m where
get = get'
...
Guess not.
Foo.hs:25:3:
The RHS of an associated type declaration mentions type variable `s'
All such variables must be bound on the LHS
What else might I be able to do? What I really want is to existentially quantify away s. I've not found any way to do that without explicit dictionary passing.
So, how do I get the benefit of fundeps for constraint families?
You can consider using a standalone type family instead of an associated type
type family StateType (m:: * -> *)
Then you can define
class MonadStateFamily m where
get' :: m (StateType m)
instance (MonadState s m, s ~ StateType m) => MonadStateFamily m where
get' = get
and use it on a concrete monad like this:
type instance StateType (State s) = s
getState :: State s s
getState = get'
Related
I have some problems using Lens library to acces Map Data type.
data Card
= Ferme
| Boulangerie
data PlayerState = PlayerState {
_psCards :: Map Card Int,
} deriving (Show)
data GameState = GameState {
_gsPlayers :: [PlayerState]
} deriving (Show)
I have difficulties accessing the Map
step :: (MonadState s m, HasGameState s, MonadIO m) => m ()
step = do
i <- use $ gsPlayers . ix 0 . psCards . ix Ferme
with the following error:
• Could not deduce (Monoid Int) arising from a use of ‘ix’
from the context: (MonadState s m, HasGameState s, MonadIO m)
bound by the type signature for:
step :: forall s (m :: * -> *).
(MonadState s m, HasGameState s, MonadIO m) =>
m ()
Is this because I use ix with different argument in the same line?
It's because ix is a Traversal, but use expects a Lens. The difference is that a Lens always has exactly one target. A Traversal can have zero or more. The combinators that expect lenses when retrieving a value sort of accidentally try to combine multiple values together as a Monoid when given a Traversal. (It comes from the Applicative instance for Const, in particular.) That attempt doesn't type check in your case because no such instance exists for the target type, so you get that error message.
You probably want the preuse combinator instead of use, to account for the value potentially not being there.
I don't have quite the vocabulary for phrasing this question (and therefore for searching for answers, so apologies if the answer is easily available). Consider the following
class RunFoo m where
runFoo :: m a -> a
class RunFooWrapper m where
doRunFoo :: (RunFoo n) => n a -> m a
newtype RunFast a = RunFast a
newtype RunSlow a = RunSlow a
fooExample :: (RunFoo m) => m Bool
fooExample = undefined
fooWrapperExample :: (RunFooWrapper m) => m Bool
fooWrapperExample = doRunFoo fooExample
This does not compile: Could not deduce (RunFoo n0) arising from a use of ‘doRunFoo’.
It seems that the compiler (GHC 7.10) is insisting on a concrete instantiation of the m from fooExample, and is therefore refusing to continue. But in this case I can't see why the program is ill-typed - fooExample explicitly defines a RunFoo m and all doRunFoo requires is a RunFoo x. So why doesn't this work?
As a supplementary question, is there some kind of special extension (something to do with existential types perhaps) that would allow a program like this? Ideally I'd like to be able to say that doRunFoo takes anything defined existentially (?) as RunFoo m => m (rather than taking any concrete instantiation of RunFoo).
Motivation
I'd like to create composable functions that operate on some aspect of a type constrained by a typeclass - I can provide a concrete example of what I mean if necessary!
Edit with more motivation and alternative implementation
I was curious about the answer to this question in the general case, but I thought I'd add that in the context I ran across this issue what I really wanted is for a sort of constrained delegation between monads. So I wanted to write functions in a monad constrained only by a typeclass that invoked monads in another type class. The top level function could then be run in different contexts, performing the same logic but with the underlying implementation swapped out according to the wrapping monad. As there was a one-to-one correspondence between the wrapping and the implementation monad I was able to use type families to do this, so
class (RunFoo (RunFooM m)) => RunFooWrapper m where
type RunFooM m :: * -> *
doRunFoo :: RunFooM m a -> m a
instance RunFooWrapper RunFooWrapperSlow where
type RunFooM RunFooWrapperSlow = RunSlow
doRunFoo :: [...]
This meant that the resolution of the fooExample m was determined by the class context of the wrapper monad, and seems to work fine, but it is a very narrow solution compared to that provided by haoformayor.
RankNTypes
{-# language RankNTypes #-}
class RunFoo m where
runFoo :: m a -> a
class RunFooWrapper m where
doRunFoo :: (forall n. RunFoo n => n a) -> m a
fooExample :: RunFoo m => m Bool
fooExample = undefined
fooWrapperExample :: RunFooWrapper m => m Bool
fooWrapperExample = doRunFoo fooExample
The (forall n. RunFoo n => n a) -> m a is the key difference. It lets you pass in fooExample, which has the type forall m. RunFoo m => m Bool (the forall being implicitly added by the compiler) and so the m unifies with the n and everybody is happy. Though I cannot read minds, I believe this type reflects your true intent. You only wanted a RunFoo instance, nothing more, and having the n scoped to the first argument provides it.
The problem was that your given code is implicitly typed as forall n. RunFoo n => n a -> m a. That means you need to first pick an n such that RunFoo n and then come up with a value with type n a to pass in as the first argument. This simple act of moving the parentheses (increasing the rank of n) changes the meaning entirely.
For an example of someone who had the same problem, see this Stack Overflow question. For a better explanation of RankNTypes than I could provide, see Oliver's blog post on it.
OK, I don't see how it can be done, but knowing that Haskell is a language of infinite depth, I decided to ask this here before giving up.
Suppose we have a value that is polymorphic, for example:
foo :: Monad m => m Int
foo = return Int
Obviously, depending on context, m can be instantiated to different types. I wonder if it's possible now to take this abstract piece of code and use it in several different contexts inside the same function (for example to reduce boilerplate when covering code):
bar :: Monad m => m Int -> Property
bar m = conjoin
[ checkIt (runIdentityT m)
, checkIt (runReaderT m ())
, …
]
Where checkIt accepts some concrete monad. Since foo is essentially abstract description how to do something, it should be possible to use it in several contexts, but the problem is obviously that if we promise to work with any Monad m => m Int in signature of bar, then we cannot write this function on less abstract level since then it's not possible to accommodate to every possible instance of Monad in its implementation.
Is there a way to pass foo into bar so it can be used in several type contexts inside it?
You want rank-2 types:
bar :: (forall m. Monad m => m Int) -> Property
bar m = conjoin
[ checkIt (runIdentityT m)
, checkIt (runReaderT m ())
, …
]
Now, bar foo will type check.
Concretely, the type (forall m. Monad m => m Int) requires the argument to be polymorphic and usable for all monads m. By comparison, the original type
bar :: Monad m => m Int -> Property
only requires the argument to have a type of the form m Int for some monad m. In your case, you clearly want "for all", and not "for some".
You can enable rank-2 types by putting at the top of your file the following line:
{-# LANGUAGE Rank2Types #-}
On a more theoretical note, my guts are telling me that the type
(forall m. Monad m => m Int)
is actually isomorphic to
Int
with isomorphisms:
iso :: Int -> (forall m. Monad m => m Int)
iso x = return x
osi :: (forall m. Monad m => m Int) -> Int
osi m = runIdentity m
The above should indeed be an isomorphism thanks to the free theorem associated to forall m. Monad m => m Int.
If my intuition is correct, as I believe, this means that every value of the type forall m. Monad m => m Int has to have the form return x for some integer x.
So, the final counter-question is: why don't you simply pass an Int, and remove the unneeded rank-2 machinery?
I'm currently trying to overload MonadTransformer extraction functions. My current attempt was to place the inner-monad m as an instance of an associated type Result:
class ( Monad Result
, MonadTrans m
, MonadReader prefix m
, ) => FooReader prefix m where
type Result
runFooReader :: forall b. m b -> prefix -> Result b
instance Monad m => FooReader prefix (ReaderT prefix m)
type Result = m -- This is there the error is thrown
runFooReader = runReaderT
The only reason why Foo is shaped funny is due to the MonadTrans and MonadReader restrictions. Basically, this is forcing all associated type instances to be monomorphic types (correct?).
I then thought to redesign it, to make Result simply a polymorphic vairable:
...
class FooReader prefix m where
runFooReader :: forall b result. m b -> prefix -> result b
... but then in the instances, the types result and w (if it's ReaderT prefix w as m, for instance) will not unify. Is there any way to make this result varialbe / idea polymorphic, yet decidable?
Cleaning up the syntax errors and adding a kind annotation to Result, we get this:
class ( Monad Result
, MonadTrans m
, MonadReader prefix m
) => FooReader prefix m where
type Result :: * -> *
runFooReader :: forall b. m b -> prefix -> Result b
instance Monad m => FooReader prefix (ReaderT prefix m) where
type Result = m -- Again, error triggered here
runFooReader = runReaderT
And a more interesting error:
The RHS of an associated type declaration mentions type variable `m'
All such variables must be bound on the LHS
This is expanded in the GHC docs:
The visibility of class parameters in the right-hand side of
associated family instances depends solely on the parameters of the
family. As an example, consider the simple class declaration
class C a b where
data T a
Only one of the two class parameters is a
parameter to the data family. Hence, the following instance
declaration is invalid:
instance C [c] d where
data T [c] = MkT (c, d) -- WRONG!! 'd' is not in scope
Here, the right-hand side of the data instance mentions
the type variable d that does not occur in its left-hand side. We
cannot admit such data instances as they would compromise type safety.
To explore the "it would compromise type safety" point, imagine this GHCi session:
> :kind! Result
Result :: * -> *
= {- ... well, what? m? -}
You probably mean type Result prefix (ReaderT prefix m) = m.
There are still errors remaining. Notably, the kind of m is inconsistent; MonadTrans needs a parameter of kind (* -> *) -> * -> * while MonadReader's second parameter needs * -> *. I don't see why you need MonadTrans.
I don't understand what you mean by "forcing all associated type instances to be monomorphic types"; the Result type you've written isn't really a type function, because it doesn't have any parameters; there aren't any type variables on its LHS.
Here's something that compiles:
class ( Monad (Result m)
, MonadReader prefix m
) => FooReader prefix (m :: * -> *) where
type Result m :: * -> *
runFooReader :: forall b. m b -> prefix -> Result m b
instance Monad m => FooReader prefix (ReaderT prefix m) where
type Result (ReaderT prefix m) = m
runFooReader = runReaderT
> :kind! Result (ReaderT Int IO)
Result (ReaderT Int IO) :: * -> *
= IO
I'm trying to write something that appears to be analagous to "rank 2 types", but for constraints instead. (Or, maybe it's not correct to assume changing -> in the definition of "rank 2 types" to => is meaningful; please edit the question if you think up better terminology).
setup
First, the Suitable typeclass (from Data.Suitable, the base of rmonad) can be used to denote types of values which can be used. In this question, I'll use
Suitable m a
to denote that value a can be used as a value for some functions of the monad m (in particular, if m is a DSL, then its values are usually a which are suitable), for example
class PrintSuitable m where
printSuitable :: Suitable m a => a -> m ()
See the top comment for RMonad [ link ] and its source for an example of how to use Suitable. For example, one could define Suitable m (Map a b), and print the number of elements in the map.
question
goal: Now, I have a monad transformer MyMonadT, and want to make MyMonadT m a PrintSuitable instance whenever m is a PrintSuitable instance.
rank 2 constraints motivation: The issue is that the type a is introduced with regard to the printSuitable function, i.e. does not appear in the class signature. Since one can only add constraints to the class signature (additional constraints to an instance function implementation are illegal), it makes sense to say something about all a in the class signature (line 2 below).
Below shows the intended code.
instance (PrintSuitable m, MonadTrans t,
(forall a. Suitable (t m) a => Suitable m a), -- rank 2 constraint
) => PrintSuitable (t m) where
printSuitable = lift ...
-- MyMonadT doesn't change what values are Suitable, hence the rank 2 expression,
-- (forall a. Suitable (t m) a => Suitable m a) should hold true
data instance Constraints (MyMonadT m) a =
Suitable m a => MyMonadT_Constraints
instance Suitable m a => Suitable (MyMonadT m) a where -- the important line
constraints = MyMonadT_Constraints
instance MonadTrans MyMonadT where ...
-- now, MyMonadT m is a PrintSuitable whenever m is a PrintSuitable
-- the manual solution, without using MonadTrans, looks roughly like this
instance PrintSuitable m => PrintSuitable (t m) where
printSuitable a = withResConstraints $ \MyMonadT_Constraints -> ...
the constraint indicated says that anything that's suitable in (t m) is suitable in m. But, of course, this isn't valid Haskell; how could one encode a functional equivalent?
Thanks in advance!!!
Doing what you asked for
If you look in my constraints package on hackage, there is
Data.Constraint.Forall
That can be used to create quantified constraints, and using inst with the other constraint combinators from the package and by making a helper constraint to put the argument in the right position, you can directly encode what you are asking for.
A description of the reflection machinery is on my blog.
http://comonad.com/reader/2011/what-constraints-entail-part-1/
http://comonad.com/reader/2011/what-constraints-entail-part-2/
However, this requires a bleeding edge GHC.
For many cases you can often ape this by making a rank 2 version of your particular constraint though.
class Monoid1 m where
mappend1 :: m a -> m a -> m a
mempty1 :: m a
but in your case you want not only a rank 2 constraint but a constraint implication.
Using the machinery from that package we could make
class SuitableLowering t m where
lowerSuitability :: Suitable (t m) a :- Suitable m a
Then you can use
instance (PrintSuitable m, SuitableLowering t m) => PrintSuitable (t m) where
and use expr \\ lowerSuitability to manually bring into scope the Suitable m a instance in a context where you know Suitable (t m) a.
But this is a really dangerous way to express an instance, because it precludes you ever making something is of kind (* -> *) -> * -> * an instance of PrintSuitable in any other way and may interfere with defining your base case if you aren't careful!
Doing what you need
The right way to do this is to give up on defining a single instance that covers all cases, and instead define a printSuitableDefault that could be used for any appropriate transformer.
Assuming the existence of RMonadTrans as mentioned in Daniel's response
class RMonadTrans t where
rlift :: Suitable m a => m a -> t m a
we can define:
printSuitableDefault :: (RMonadTrans t, Suitable m a) => a -> t ()
printSuitableDefault = ...
instance PrintSuitable m => PrintSuitable (Foo m) where
printSuitable = printSuitableDefault
instance PrintSuitable m => PrintSuitable (Bar m) where
printSuitable = printsuitableDefault
You aren't likely to have too many rmonad transformers, and this ensures that if you want to make one print a different way you have that flexibility.
Doing what you need slightly more nicely under a bleeding edge compiler
Under 7.3.x (current GHC HEAD) or later you can even use the new default declarations to make this a little less painful.
class RMonad m => PrintSuitable m where
printSuitable :: a -> m ()
default printSuitable :: (RMonadTrans t, RMonad n, Suitable n a, m ~ t n) =>
a -> t n ()
printSuitable = <the default lifted definition>
then the instances for each transformer can just look like:
instance PrintSuitable m => PrintSuitable (Foo m)
instance PrintSuitable m => PrintSuitable (Bar m)
and you can define your nice printSuitable base case for some retricted monad without worries about overlap.
I don't think MonadTrans will be of use here, since lift requires m to be a Monad. Can you work with
class RMonadTrans t where
rlift :: Suitable m a => m a -> t m a
instance (RMonadTrans t, Suitable m a) => Suitable (t m) a where
constraints = ???
A related thing is that you can define an instance:
{-# LANGUAGE FlexibleInstances, FlexibleContexts,
UndecidableInstances, MultiParamTypeClasses #-}
module Foo where
import Control.Monad.Trans
class Suitable m a where
foo :: m a -> Int
class PrintSuitable m where
printSuitable :: Suitable m a => a -> m ()
instance (PrintSuitable m, MonadTrans t, Suitable (t m) a) => Suitable m a where
foo = const 5
instance (PrintSuitable m, MonadTrans t) => PrintSuitable (t m) where
printSuitable = undefined
So you don't need the constraint. Will that help?