Lens access Map Key - haskell

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.

Related

Why does this type annotation make my functional dependency conflict go away? (and why does it only happen on some versions of GHC?)

So I've been playing around with MonadState class and I have encountered something I consider very strange.
I can try to write a monad like the following:
test ::
( MonadState Int m
, MonadState Bool m
)
=> m ()
test = do
((+1) <$> get) >>= put
(not <$> get) >>= put
If we compile this in ghc 8.6.4 we get the following:
MonadTrans.hs:10:13: error:
• Couldn't match type ‘Int’ with ‘Bool’
arising from a functional dependency between constraints:
‘MonadState Bool m’
arising from a use of ‘get’ at MonadTrans.hs:10:13-15
‘MonadState Int m’
arising from the type signature for:
test :: forall (m :: * -> *).
(MonadState Int m, MonadState Bool m) =>
m ()
at MonadTrans.hs:(4,1)-(8,11)
• In the second argument of ‘(<$>)’, namely ‘get’
In the first argument of ‘(>>=)’, namely ‘((+ 1) <$> get)’
In a stmt of a 'do' block: ((+ 1) <$> get) >>= put
|
10 | ((+1) <$> get) >>= put
|
(older versions of GHC for example 8.2.2 are actually fine with this and compile. I have no idea why.)
Ok this makes sense since the declaration of MonadState has a dependency in it:
class Monad m => MonadState s m | m -> s where
we cannot have a single Monad be both MonadState Int and MonadState Bool. But here is where things get a little strange.
If I add a type annotation the code will compile
test ::
( MonadState Int m
, MonadState Bool m
)
=> m ()
test = do
(((+1) :: Int -> Int) <$> get) >>= put
(not <$> get) >>= put
To me this seems very strange. A moment ago it was complaining about a very real functional dependency conflict between the two. I don't see how disambiguating the type of (+1) makes that conflict go away.
What is happening here? How does the second one compile while the first fails? And why does the first compile on 8.2.2?
Try this:
plus1 :: Int -> Int
plus1 = (+ 1)
test :: (MonadState Int m, MonadState Bool m) => m ()
test = do
(plus1 <$> get) >>= put
(not <$> get) >>= put
Compiles fine, even without the inline type annotation.
What the functor?!
The thing is, when the compiler complains in your first example, it doesn't complain about the type signature just because it decided to verify it for the heck of it. Look a bit further in the error message: ...In the second argument of ‘(<$>)’, namely ‘get’...
Aha! The source of trouble is actually get! But why?
The trouble is the bloody overloaded arithmetic. You see, operator (+) has a polymorphic type, like this:
(+) :: Num a => a -> a -> a
And naked literals also have similar type:
1 :: Num a => a
So when you write (+1), it doesn't let the compiler know that you meant Int. It admits any type a as long as there is Num a.
So the compiler turns to further surroundings to get the type. But wait! Further surroundings are also generic:
get :: MonadState a m => m a
put :: MonadState a m => a -> m ()
Ok, so maybe we can get the type from the signature of test? Let's check that! Oh, no, the signature actually contains a conflict! Bail, bail, bail! That's when you get the error.
All of this doesn't happen on the second line, because not has a non-polymorphic type not :: Bool -> Bool, so the required type of get is known. And this is why either giving an inline type annotation Int -> Int or having it come from an external function plus1 helps on the first line as well.
If you do provide enough type information for the values in the body, the compiler never has to analyze the test signature. The signature specifies that there should be a MonadState Int m dictionary, and that's good enough. Whoever calls the function will have provide the dictionary, and we'll just use that.
Now, of course, when you get around to calling this function, you'll need to provide both dictionaries MonadState Int m and MonadState Bool m, and you can't get those, so you can't actually call such function. But you sure can define it.
That being said, you CAN actually have a monad with two different MonadState instances if you're willing to be sneaky enough about it.
Of course, if you try it straight up, you get a very straight up error:
data M a = M
instance MonadState Int M
instance MonadState Bool M
> Functional dependencies conflict between instance declarations:
> instance MonadState Int M -- Defined at ...
> instance MonadState Bool M -- Defined at ...
Ok, let's start small:
data M a = M
instance MonadState Int M
> Illegal instance declaration for `MonadState a M'
> The liberal coverage condition fails in class `MonadState'
> for functional dependency: `m -> s'
> Reason: lhs type `M' does not determine rhs type `a'
> Un-determined variable: a
Alright, so something in the type of M must indicate the type Int. That makes sense. Let's add it:
data M x a = M a
instance MonadState Int (M Int)
Ok, this works. So far so good.
But of course, in order to define MonadState Bool, I need to add Bool to the type as well:
data M x y a = M a
instance MonadState Int (M Int y)
instance MonadState Bool (M x Bool)
> Functional dependencies conflict between instance declarations:
Ah, still fundep failure! Ok, well, that makes sense too.
So is there a way I can fool the compiler into not checking the instances for the fundep? Yes, there is! I can be sneaky and make the instances overlapped, like this:
instance {-# OVERLAPPABLE #-} (Num a, Show a) => MonadState a (M a y) where
get = M 42
put x = M ()
instance {-# OVERLAPPING #-} MonadState Bool (M x Bool) where
get = M True
put x = M ()
Now all that's left is the Monad instance, and we can have it all actually run:
data M x y a = M a deriving (Functor, Show)
instance Applicative (M x y) where
pure = M
(M f) <*> (M x) = M $ f x
instance Monad (M x y) where
(M x) >>= f = f x
instance {-# OVERLAPPABLE #-} (Num a, Show a) => MonadState a (M a y) where
get = M 42
put x = trace ("Setting Num: " ++ show x) $ M ()
instance {-# OVERLAPPING #-} MonadState Bool (M x Bool) where
get = M True
put x = trace ("Setting Bool: " ++ show x) $ M ()
g :: M Int Bool ()
g = test
main = print g
I've included debug trace to verify how they're actually going to work, so the above program prints:
Setting Num: 43
Setting Bool: False
M ()

Separating concerns in a DSL using MTL

I'm writing a small DSL using monad-transformers following the ideas presented
here here. For the sake of
illustration I present a small subset here.
class Monad m => ProjectServiceM m where
-- | Create a new project.
createProject :: Text -- ^ Name of the project
-> m Project
-- | Fetch all the projects.
getProjects :: m [Project]
-- | Delete project.
deleteProject :: Project -> m ()
The idea of this DSL is to be able to write API-level tests. To this end, all
these actions createProject, getProjects, deleteProject will be
implemented by REST calls to a web-service.
I also wrote an DSL to write expectations. An snippet is given below:
class (MonadError e m, Monad m) => ExpectationM e m | m -> e where
shouldContain :: (Show a, Eq a) => [a] -> a -> m ()
And you could imagine that more DSL's can be added to the mix for logging, and
performance metrics see the gist linked above.
With these DSL is possible to write some simple tests like the following:
createProjectCreates :: (ProjectServiceM m, ExpectationM e m) => m ()
createProjectCreates = do
p <- createProject "foobar"
ps <- getProjects
ps `shouldContain` p
Two interpreters are shown below:
newtype ProjectServiceREST m a =
ProjectServiceREST {runProjectServiceREST :: m a}
deriving (Functor, Applicative, Monad, MonadIO)
type Error = Text
instance (MonadIO m, MonadError Text m) => ProjectServiceM (ProjectServiceREST m) where
createProject projectName = return $ Project projectName
getProjects = return []
deleteProject p = ProjectServiceREST (throwError "Cannot delete")
newtype ExpectationHspec m a =
ExpectationHspec {runExpectationHspec :: m a}
deriving (Functor, Applicative, Monad, MonadIO)
instance (MonadError Text m, MonadIO m) => ExpectationM Text (ExpectationHspec m) where
shouldContain xs x = if any (==x) xs
then ExpectationHspec $ return ()
else ExpectationHspec $ throwError msg
where msg = T.pack (show xs) <> " does not contain " <> T.pack (show x)
Now to run the scenario createProjectCreates the monad transformers can be
stacked in different ways. One way I found it makes sense is:
runCreateProjectCreates :: IO (Either Text ())
runCreateProjectCreates = ( runExceptT
. runExpectationHspec
. runProjectServiceREST
) createProjectCreates
Which requires:
instance ProjectServiceM (ProjectServiceREST (ExpectationM (ExceptT Text IO)))
instance ExpectationM Text (ProjectServiceREST (ExpectationM (ExceptT Text IO)))
The problem with this is that either the instances of ProjectSeviceM have to
know about ExpectationM and create instances for it, or vice-versa. These
instances can be readily created by using the StandaloneDeriving extension, e.g.:
deriving instance (ExpectationM Text m) => ExpectationM Text (ProjectServiceREST m)
However it'd be nice if this could be avoided, since I'm leaking some
information to either implementations of the DSL's. Can the problem above be
overcome?
The concrete constructors for your monad stack don't have to correspond directly to the mtl-style type classes. This article and Reddit discussion are relevant. The mtl class MonadState s m has a generic dumb implementation in StateT, but you can instantiate MonadState for ReaderT (IORef s) IO too, or for a CPS variant. Ultimately, you remain abstract in how you want the effect to be handled, you just require that it is handled.
Suppose instead you wrote two abstract monad transformers:
newtype ProdT m a = ProdT { runProdT :: ... }
deriving (Functor, Applicative, Monad, MonadTrans, ...)
newtype TestT m a = TestT { runTestT :: ... }
deriving (Functor, Applicative, Monad, MonadTrans, ...)
and you then define the instances you require. Instead of needing to write all the pass through instances, you can just write the ones you need directly.
As an aside, I would recommend not defining type classes if they are trivial combinations of other classes. The class/instance definitions for
class (MonadError e m, Monad m) => ExpectationM e m | m -> e where
shouldContain :: (Show a, Eq a) => [a] -> a -> m ()
works just as well as
shouldContain :: (MonadError e m, Show a, Eq a) => [a] -> a -> m ()
You already have the ability to alter the base monad, as long as it has MonadError. A test implementation would possibly be
newtype ExpectationT m e a = ExpectationT { runExpectation :: WriterT [e] m a }
instance Monad m => MonadError (ExpectationT m e) e where
throwError = ExpectationT . tell
-- etc..

Is it possible to instantiate polymorphic piece of code differently in the same function?

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?

Function from `mappend` function to `Monoid` instance?

I have a data structure (it's a specific subclass of rose-tree that forms a lattice with greatest-lower bound and lowest-upper bound functions), and it supports two perfectly reasonable functions to serve as the Monoid class's mappend.
Is there any way to support anonymous Monoid instances in haskell? Is this an instance where I should consider using something like Template-Haskell to generate my typeclasses for me?
What I'd love is a makeMonoid :: (RT a -> RT a -> RT a) -> Monoid a to let me create the instance on the fly, but I understand that that's incoherent with the stock typesystem as I understand it.
I'm okay with it if I just need to pick a default merge function and write newtypes for other merges, just curious
You can create "local" instances of Monoid on the fly, using the tools in the reflection package. There's a ready-made example in the repository. This answer explains it a little.
This is a newtype wrapper over values of type a, on which we will define our Monoid instance.
newtype M a s = M { runM :: a } deriving (Eq,Ord)
Notice that there is a phantom type s that does not appear in the right hand side. It will carry extra information necessary for the local Monoid instance to work.
This is a record whose fields represent the two operation of the Monoid class:
data Monoid_ a = Monoid_ { mappend_ :: a -> a -> a, mempty_ :: a }
The following is the Monoid instance definition for M:
instance Reifies s (Monoid_ a) => Monoid (M a s) where
mappend a b = M $ mappend_ (reflect a) (runM a) (runM b)
mempty = a where a = M $ mempty_ (reflect a)
It says: "whenever s is a type-level representation of our Monoid dictionary Monoid_, we can reflect it back to obtain the dictionary, and use the fields to implement the Monoid operations for M".
Notice that the actual value a passed to reflect is not used, it is passed only as a "proxy" of type M a s that tells reflect which type (s) to use to "bring back the record".
The actual local instance is constructed using the reify function:
withMonoid :: (a -> a -> a) -> a -> (forall s. Reifies s (Monoid_ a) => M a s) -> a
withMonoid f z v = reify (Monoid_ f z) (runM . asProxyOf v)
asProxyOf :: f s -> Proxy s -> f s
asProxyOf a _ = a
The asProxyOf function is a trick to convince the compiler that the phantom type used in the monoid is the same as the one in the Proxy supplied by reify.

Fundeps for constraint families

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'

Resources