I am trying to replace StateT with AccumT in my program but I can't figure out exactly how it works. Specifically, I don't understand why runAccumT and its derivatives seem to ignore their second argument. For example, I was expecting
execAccumT (add 7) 8 :: IO Int
to print 15, but it prints 7. What am I missing here?
Updated with a workaround.
First, note that
Accumuses a generalMonoid, not just a sum, so even though your code happens to work because it involves only one monadicadd, anything that actually involved multiple accumulator operations would fail to type check:Instead, as in @DanielWagner's answer, you need to use the
Summonoid:You can continue to write
add 7instead ofadd (Sum 7)becauseSum Inthas aNuminstance that automatically converts numeric literatals to sums, and allows simple arithmetic operations on them, but if you wanted toadd xwherex :: Int, you'd need to writeadd (Sum x)explicitly.Second, there does appear to be a bug in the handling of the initial value of the accumulator, what the documentation calls its "initial history". If you write:
it appears that the initial history is ignored, but if you use
runAccumTto simultaneously inspect both whatlookthinks is the final history, and the final history returned byrunAccumT, you can see a discrepancy:That is,
look's opinion of the final history is that it includes the initial history, but the final history returned byrunAccumTdoesn't include the initial history.For now, it's safe to use
Accumwith an "mempty" initial history, i.e., whatever is the appropriate zero value for theMonoid, and use an initialaddoperation if you want to start with something other thanmempty.If you want to use a non-
memptyhistory, I suggest importing with a few functions hidden and use these replacements:These should work fine: