Open byorgey opened 3 years ago
Edited to add: it turns out that it works (i.e. both print 1) if we switch the order of the strategies CS.Field "r" ()
and CR.ReadStatePure
in the derivation of HasReader
for M2
. I don't really understand why this should make a difference. If this is in fact expected behavior, then at the very least I think the documentation ought to be improved/clarified; I don't remember seeing anything warning me of this pitfall.
@byorgey Thank you for reporting! This is indeed expected behavior. I agree that this should be clarified better in the docs.
The following ordering
deriving (CR.HasReader "r" Char, CSc.HasSource "r" Char) via
(CS.Field "r" ()
(CR.ReadStatePure
(CS.MonadState
(MS.State S))))
first creates a reader in the record S
and only then focuses in on the field r
in the reader's context. I.e. the underlying implementation of local
will operate on the full record S
and will reset the whole record at the end of local
. In effect the writer and reader capability overlap on the field w
of the record S
.
On the other hand, if the order of Field
and ReadStatePure
is swapped, then the underlying implementation of local
will operate only on the field r
. I.e. the following is the correct ordering.
deriving (CR.HasReader "r" Char, CSc.HasSource "r" Char) via
(CR.ReadStatePure
(CS.Field "r" ()
(CS.MonadState
(MS.State S))))
Ah, I get it now, thanks for the explanation! I suggest... a big fat warning attached to the Field
combinator? Or the ReadStatePure
combinator? Or both?
I wonder if there could be a way to prevent or warn about this. It is unfortunate that there are valid ways to compose the strategies that give bogus results. You need a type system for your type-level strategy combinators... =)
Describe the bug Sometimes an enclosing call to 'local' for a particular Reader capability causes the accumulated value for a (conceptually unrelated) Writer capability to be reset. This only seems to happen when the concrete monad implementing the capabilities stores the values in the same record, though it's possible the record thing is a red herring.
To Reproduce
Below is the smallest example I have been able to come up with.
Expected behavior I expect the above code to print 1 twice; which concrete monad + deriving strategies we use should not change the semantics of 'act', especially when only Reader + Writer are involved (which should commute etc.) and there are no IO or exceptions anywhere to be seen.
Instead, the above code prints 1, then 0.
Environment