I wound up emailing John Millikin about this and he made a good case against these kinds of simplified operators, which is basically the problem of handling left-over input. The joinI and joinE combinators discard the left-over Stream that is yielded by the inner iteratee. (As John explains it, this is a trade-off between ease of use and programming complexity.) Simplified operators (like $=, =$, and now =$=) use repeated joinI&#39;s, so left-over input may be lost in various places. When using simple iteratees that never yield left-over input, this isn&#39;t a problem and the operators make sense.<div>

<br></div><div>For more complex pipelines, John advocates a style like this:</div><div><br></div><div><span style>joinI (foo $$ (bar $$ baz))</span><br style></div><div><span style><br></span></div><div><span style>so that left over data is only discarded once after the computation is otherwise complete.</span></div>

<div><span style><br></span></div><div><span style>In any case, there&#39;s now a new release of enumerator (0.4.17) which includes an enumeratee composition operator: (=$=) :: </span><font color="#222222" face="arial, sans-serif">Monad m =&gt; Enumeratee a1 a2 m (Step a3 m b) -&gt; Enumeratee a2 a3 m b -&gt; Enumeratee a1 a3 m b.</font></div>

<div><br></div><div>Cheers,<br clear="all">Mike Craig<br><br><br><div class="gmail_quote">On Tue, Dec 27, 2011 at 10:12 AM, Michael Craig <span dir="ltr">&lt;<a href="mailto:mkscrg@gmail.com">mkscrg@gmail.com</a>&gt;</span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>Thanks for the replies, all. It&#39;s good to see that the other iteratee packages out there are addressing this issue.</div>

<div><br></div><div>I still don&#39;t get why it&#39;s an issue in the first place. It seems to me like a pretty simple thing to implement:</div>
<div><br></div><div><div>(=$=) :: (Monad m)</div><div>      =&gt; Enumeratee a0 a1 m (Step a2 m b) -&gt; Enumeratee a1 a2 m b</div><div class="im"><div>      -&gt; Enumeratee a0 a2 m b</div></div><div>(=$=) e01 e12 step = Iteratee $ do</div>

<div>
    step&#39; &lt;- runIteratee $ e12 step</div><div>    runIteratee . joinI $ e01 step&#39;</div></div><div><br></div><div>This puts a type restriction on the LHS enumeratee, but enumeratees are generally polymorphic in the last type param anyway. (And joinE has a similar restriction when composing an enumerator with an enumeratee.)</div>


<div><br></div><div>Is there a good reason why enumerator doesn&#39;t export this or something analogous?</div><br clear="all">Mike Craig<div class="HOEnZb"><div class="h5"><br><br><br><div class="gmail_quote">On Sun, Dec 25, 2011 at 10:20 PM, Conrad Parker <span dir="ltr">&lt;<a href="mailto:conrad@metadecks.org" target="_blank">conrad@metadecks.org</a>&gt;</span> wrote:<br>




<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div>On 24 December 2011 05:47, Michael Craig &lt;<a href="mailto:mkscrg@gmail.com" target="_blank">mkscrg@gmail.com</a>&gt; wrote:<br>





&gt; I&#39;ve been looking for a way to compose enumeratees in the enumerator<br>
&gt; package, but I&#39;ve come up with nothing so far. I want this function<br>
&gt;<br>
&gt; (=$=) :: Monad m =&gt; Enumeratee a0 a1 m b -&gt; Enumeratee a1 a2 m b -&gt;<br>
&gt; Enumeratee a0 a2 m b<br>
&gt;<br>
&gt; I&#39;m building a modular library on top of enumerator that facilitates reading<br>
&gt; time series data from a DB, applying any number of transformations to it,<br>
&gt; and then writing it back / doing something else with it. I&#39;d like to be able<br>
&gt; to write simple transformations (enumeratees) and compose them without<br>
&gt; binding them to either a db reader (enumerator) or db writer (iteratee).<br>
&gt;<br>
&gt; I&#39;ve been looking at the iterIO package as a possible alternative, because<br>
&gt; it seems to allow easy composition of Inums (enumeratees). I&#39;m a little<br>
&gt; skittish of it because it seems unpopular next to enumerator.<br>
<br>
</div></div>Hi Michael,<br>
<br>
You could also look at the iteratee package. This is the signature of<br>
the (&gt;&lt;&gt;) operator:<br>
<br>
(&gt;&lt;&gt;) :: (Nullable s1, Monad m) =&gt; (forall x. Enumeratee s1 s2 m x) -&gt;<br>
Enumeratee s2 s3 m a -&gt; Enumeratee s1 s3 m a<br>
<br>
it&#39;s quite useful for composing enumeratees, likewise its friend (&lt;&gt;&lt;)<br>
swims the other way.<br>
<br>
<a href="http://hackage.haskell.org/packages/archive/iteratee/0.8.7.5/doc/html/Data-Iteratee-Iteratee.html" target="_blank">http://hackage.haskell.org/packages/archive/iteratee/0.8.7.5/doc/html/Data-Iteratee-Iteratee.html</a><br>





<br>
cheers,<br>
<br>
Conrad.<br>
</blockquote></div><br>
</div></div></blockquote></div><br></div>