Hi all,<div><br></div><div><div>I&#39;d say that a type class declares functions and specifies laws (in the docs)</div><div>what its implementations must adhere to. It&#39;s not the job of a type class to</div><div>fulfill the laws, it&#39;s the job of its implementations. So the reason for</div>

<div>&#39;Monoid w&#39; in &#39;MonadWriter&#39; cannot be that then &#39;MonadWriter&#39; wouldn&#39;t be a</div><div>monad. Such constraints should be required only by implementations.</div><div><br></div><div>It is true that any Writer has an implicit underlying monoid, and we can even &quot;extract&quot; the operations from it as follows. The empty element can be extracted as</div>

<div><br></div><div>     empty = liftM snd (listen (return ())) :: m w</div><div><br></div><div>Having this &#39;empty&#39;, we can give &#39;const empty&#39; to &#39;pass&#39; to discard output of</div><div>an action, so we can construct:</div>

<div><br></div><div>    -- | @contained m@ executes the action @m@ in a contained environment and</div><div>    -- returns its value and its output. The current output is not modified.</div><div>    contained :: m a -&gt; m (a, w)</div>

<div>    contained k = do</div><div>        -- we can retrieve mempty even if we don&#39;t have the monoid constraint:</div><div>        ~(_, empty) &lt;- listen (return ())</div><div>        -- listen what @k@ does, get its result and ignore its output change:</div>

<div>        pass (listen k &gt;&gt;= \x -&gt; return (x, const empty))</div><div><br></div><div>This generalizes &#39;listen&#39; and &#39;pass&#39; (both can be easily defined from it) and I find this function much easier to understand. In a way, it is also a generalization of WriterT&#39;s runWriterT, because for WriterT we have</div>

<div>&#39;contained = lift . runWriterT&#39;.</div><div><br></div><div>[I implemented &#39;contained&#39; in a fork of the mtl library, if anybody is</div><div>interested: <a href="https://github.com/ppetr/mtl">https://github.com/ppetr/mtl</a> ]</div>

<div><br></div><div>With that, we can do</div><div><br></div><div>    -- Doesn&#39;t produce any output, only returns the combination</div><div>    -- of the arguments.</div><div>    append x y = liftM snd $ contained (tell x &gt;&gt; tell y) :: w -&gt; w -&gt; m w</div>

<div><br></div><div>I didn&#39;t check the monoid laws, but it seems obvious that they follow from the</div><div>monad laws and (a bit vague) specification of &#39;listen&#39; and &#39;pass&#39;.</div><div><br></div><div>

Personally, I&#39;d find it better if `MonadWriter` would be split into two levels:</div><div>One with just &#39;tell&#39; and &#39;writer&#39; and the next level extending it with</div><div>&#39;listen&#39;/&#39;pass&#39;/&#39;contained&#39;. The first level would allow things like logging to</div>

<div>a file, without any monoidal structure. But this would break a lot of stuff</div><div>(until we agree on and develop something like <a href="http://hackage.haskell.org/trac/ghc/wiki/DefaultSuperclassInstances">http://hackage.haskell.org/trac/ghc/wiki/DefaultSuperclassInstances</a>).</div>

<div><br></div><div>    Best regards,</div><div>    Petr</div></div><div><br></div><div class="gmail_extra"><br><br><div class="gmail_quote">2012/12/9 Roman Cheplyaka <span dir="ltr">&lt;<a href="mailto:roma@ro-che.info" target="_blank">roma@ro-che.info</a>&gt;</span><br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">* Edward Z. Yang &lt;<a href="mailto:ezyang@MIT.EDU">ezyang@MIT.EDU</a>&gt; [2012-12-08 15:45:54-0800]<br>
<div class="im">&gt; &gt; Second, even *if* the above holds (two tells are equivalent to one<br>
&gt; &gt; tell), then there is *some* function f such that<br>
&gt; &gt;<br>
&gt; &gt;     tell w1 &gt;&gt; tell w2 == tell (f w1 w2)<br>
&gt; &gt;<br>
&gt; &gt; It isn&#39;t necessary that f coincides with mappend, or even that the type<br>
&gt; &gt; w is declared as a Monoid at all. The only thing we can tell from the<br>
&gt; &gt; Monad laws is that that function f should be associative.<br>
&gt;<br>
&gt; Well, the function is associative: that&#39;s half of the way there to<br>
&gt; a monoid; all you need is the identity!  But we have those too:<br>
&gt; whatever the value of the execWriter (return ()) is...<br>
<br>
</div>Let me repeat:<br>
<div class="im"><br>
  It isn&#39;t necessary that f coincides with mappend, or even that the<br>
  type w is declared as a Monoid at all.<br>
<br>
</div>Let me illustrate this with an example.<br>
<br>
  data MyWriter a = MyWriter Integer a<br>
<br>
  instance Monad MyWriter where<br>
    return = MyWriter 0<br>
    MyWriter n x &gt;&gt;= k =<br>
      let MyWriter n&#39; y = k x<br>
      in MyWriter (n+n&#39;) y<br>
<br>
  instance MonadWriter Integer MyWriter where<br>
    tell n = MyWriter n ()<br>
    listen (MyWriter n x) = return (x,n)<br>
    pass (MyWriter n (a,f)) = MyWriter (f n) a<br>
<br>
Yes, integers do form a monoid when equipped with 0 and (+). However, we<br>
know well why they are not an instance of Monoid — namely, there&#39;s more<br>
than one way they form a monoid.<br>
<br>
Even if something is in theory a monoid, there may be technical reasons<br>
not to declare it a Monoid. Likewise, imposing a (technical) superclass<br>
constraint on MonadWriter has nothing to do with whether the Monad will<br>
be well-behaved.<br>
<br>
This is true in both directions: even if the type is an instance of<br>
Monoid, nothing forces the Monad instance to use the Monoid instance.<br>
I.e. I can declare a MonadWriter on the Sum newtype whose bind, instead<br>
of adding, subtracts the numbers.<br>
<span class="HOEnZb"><font color="#888888"><br>
Roman<br>
</font></span></blockquote></div><br></div>