title: How do I write this more general version of `Control.Monad.Writer.censor`?
body: <p>The standard <code>Control.Monad.Writer.censor</code> is dual to the standard
  <code>Control.Monad.Reader.local</code>, with <code>censor</code> modifying the writer state
  <em>after</em> the computation and <code>local</code> modifying the reader state
  <em>before</em> the computation:</p>
  
  <pre><code>censor :: (w -&gt; w) -&gt; Writer w a -&gt; Writer w a
  local  :: (r -&gt; r) -&gt; Reader r a -&gt; Reader r a
  </code></pre>
  
  <p>However, the <code>Reader</code> and <code>Writer</code> monads are not entirely
  symmetric. Namely, a writer computation produces a <em>result</em>, in
  addition to a writer state, and I'm trying to write an alternative
  version of <code>censor</code> that takes advantage of this asymmetry.  I want to
  write a function</p>
  
  <pre><code>censorWithResult :: (a -&gt; w -&gt; w) -&gt; Writer w a -&gt; Writer w a
  </code></pre>
  
  <p>which takes a transformer of type <code>a -&gt; w -&gt; w</code> that receives the
  result of the computation <em>in addition</em> to the writer state.  I don't
  see how to write this function using <code>tell</code>, <code>listen</code>, and <code>pass</code>.</p>
  
  <p>The precise behavior I expect of <code>censorWithResult</code> is that if</p>
  
  <pre><code>ma :: Writer w a
  f  :: a -&gt; w -&gt; w
  </code></pre>
  
  <p>and</p>
  
  <pre><code>runWriter ma = (r , y)
  </code></pre>
  
  <p>then</p>
  
  <pre><code>runWriter (censorWithResult f ma) = (r , f r y)
  </code></pre>
  
  <p>whereas</p>
  
  <pre><code>runWriter (censor g ma) = (r , g y)
  </code></pre>
  
  <p>when <code>g :: w -&gt; w</code>.</p>
  
  <h1>Example</h1>
  
  <p>This shouldn't be necessary to understand the question, but here's a
  simplified version of the motivating example:</p>
  
  <pre><code>import Control.Applicative
  import Control.Monad.Writer
  
  -- Call-trace data type for functions from 'Int' to 'Int'.
  --
  -- A 'Call x subs r' is for a call with argument 'x', sub calls
  -- 'subs', and result 'r'.
  data Trace = Call Int Forest Int
  type Forest = [Trace]
  
  -- A writer monad for capturing call traces.
  type M a = Writer Forest a
  
  -- Recursive traced negation function.
  --
  -- E.g. we expect that
  --
  --   runWriter (t 2) = (-2 , Call 2 [Call 1 [Call 0 [] 0] -1] -2)
  t , n :: Int -&gt; M Int
  t x = trace n x
  n x = if x &lt;= 0 then pure 0 else subtract 1 &lt;$&gt; t (x - 1)
  
  trace :: (Int -&gt; M Int) -&gt; (Int -&gt; M Int)
  trace h x = do
    censorWithResult (\r subs -&gt; [Call x subs r]) (h x)
  
  -- The idea is that if 'ma :: Writer w a' and 'runWriter ma = (r , y)'
  -- then 'runWriter (censorWithResult f ma) = (r , f r y)'. I.e.,
  -- 'censorWithResult' is like 'Control.Monad.Writer.censor', except it
  -- has access to the result of the 'Writer' computation, in addition
  -- to the written data.
  censorWithResult :: (a -&gt; w -&gt; w) -&gt; Writer w a -&gt; Writer w a
  censorWithResult = undefined
  </code></pre>