Relationship between tags and record field names
aherrmann opened this issue · 3 comments
In the current implementation the instance tag, i.e. tag
in HasState tag s m
, is unrelated to any potential record field labels in the state type. E.g. the following instances (MonadState
, and Field
)
instance State.MonadState s m => HasState tag s (MonadState m)
instance ( Generic s', Generic.HasField' field s' s, HasState tag s' m )
=> HasState tag s (Field field m)
exist for any tag
.
Consider the following example.
data MyState = MyState { msFoo :: Int }
deriving Generic
newtype MyStateM a = MyStateM (State MyState a)
deriving (Functor, Applicative, Monad)
deriving (HasState "foo" Int) via
Field "msFoo" (MonadState (State MyState))
The field label msFoo
and the tag foo
are unrelated.
Alternatively, we could enforce that the tag
and record field
match. For nested records, or other situations where this may not be the case, we could introduce a Rename
combinator. The above example could then look like this.
newtype MyStateM' a = MyStateM' (State MyState a)
deriving (Functor, Applicative, Monad)
deriving (HasState "foo" Int) via
Rename "foo" (Field "msFoo" (MonadState (State MyState)))
where MonadState
would still exist for any tag
, but Field
requires that tag
and field
match.
As a side note, for non-records a Position
combinator could be introduced that uses HasPosition'
from generic-lens
.
See #7 (comment)
cc @aspiwack
Thanks for this issue.
As a side note, for non-records a Position combinator could be introduced that uses HasPosition' from generic-lens.
This sounds quite reasonable, indeed.
Both options seem to have their inconveniences. I think naming the capability after the field is less surprising. It improves composability somehow, as per the comment linked in the issue, it's not clear that it's a useful improvement.
But having the tag be arbitrary is less verbose. For instance, we would need, to be able to write the instance for Field
to add an extra argument in Field
for the tag of the capability we're modifying.
I don't have a conclusion. It needs to be pondered carefully.
I don't have a conclusion. It needs to be pondered carefully.
I agree, #12 explores a possible direction to implement this.
For instance, we would need, to be able to write the instance for Field to add an extra argument in Field for the tag of the capability we're modifying.
At least in #12 that doesn't seem to be the case. However, due to the functional dependency on HasState tag s m
, namely tag m -> s
, it seems that we need a second argument on Rename
, namely Rename newtag oldtag
.