I'm a bit confused and don't know where to look for the information/explanation of the following "issue" (it's not an issue per se, but more of a situation where I don't understand what is wrong behind the scenes):
I have a monad transformer stack with StateT. At some point in my function I would like to bind a small fraction of my state into the local variable so I can refer to it instead of writing out the whole path to the chunk of the state I'm interested in. Here is what I mean:
{-# LANGUAGE ScopedTypeVariables #-}
...
someFunction :: MyMonad ()
someFunction = do
...
let x :: Traversal' MyState MyDataT = myState.clients.ix clientIdx.someData.ix dataIdx
...
Now this doesn't compile:
Couldn't match type ‘(MyDataT -> f0 MyDataT)
-> MyState -> f0 MyState’
with ‘forall (f :: * -> *).
Control.Applicative.Applicative f =>
(MyDataT -> f MyDataT) -> MyState -> f MyState’
But if I move the referencing of this data chunk into a function then everything compiles ok:
someFunction :: MyMonad ()
someFunction = do
...
let x = clientData clientIdx dataIdx
...
where clientData :: Int -> Int -> Traversal' MyState MyDataT
clientData clientIdx dataIdx = myState.clients.ix clientIdx.someData.ix dataIdx
I'm looking for some kind of information that will help me understand what is going on here, why it happens, so that I'm aware of what I'm doing wrong. Basically I would like to expand my knowledge to understand this use case a bit better.
The key point here is that the annotation should be in a separate line. If we do that, then we have a binding with an explicit type, as far as GHC is concerned.
What you first tried very rarely works as you intended:
This is a binding without an explicit type; the annotation is inside the left hand side. GHC considers the type of the variable fixed before looking at the right hand side, but the annotation only applies to the left hand side, so GHC just infers a type for the right had side separately, and then tries to match it exactly with the annotation. This makes the type checking fail for all but the simplest non-polymorphic cases.
The right way of putting annotations inside bindings is the following:
Here, GHC first assigns a "malleable" indeterminate type variable to
x
, then infers a type for the right side informed by the annotation there, then unifies the type ofx
with it.This is still a binding without an explicit type, but it works in general if we enable
NoMonomorphismRestriction
, for reasons detailed in this SO question.