<div class="gmail_quote"><div>At first I regarded this as simply a bug in the Iteratee.map definition, but like Ben, it's started to bother me a lot. I think this is precisely the sort of issue a proper denotational semantics would fix.</div>
<div><br></div><div>Unfortunately the only general solution I see is to abandon chunking and work strictly element-wise. I say unfortunately because my current best implementation is about 5 times slower than the main tree. I'm open to ideas.</div>
<div><br></div><div>John</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">From: Ben <<a href="mailto:midfield@gmail.com">midfield@gmail.com</a>><br>
<br>
Sorry to be late coming into this conversation.....<br>
<br>
Something that has bothered me (which I have mentioned to John Lato<br>
privately) is that it is very easy to write non-compositional code due<br>
to the chunking. For example, there is a standard function<br>
<br>
map :: (a -> b) -> Enumeratee a b c<br>
<br>
whose meaning I hope is clear : use the function to transform the type<br>
of a stream and pass it to an iteratee. However last I checked the<br>
versions provided in both the iteratee and enumerator packages fail to<br>
satisfy the equation<br>
<br>
map f (it1 >> it2) == (map f it1) >> (map f it 2)<br>
<br>
because of chunking, essentially. You can check this with f == id and<br>
it1 and it2 are head:<br>
<br>
let r = runIdentity . runIteratee<br>
<br>
runIdentity $ run $ enumList 10 [1..100] $ r $ joinI $ map id $ r (head >> head)<br>
--> Right (Just 2)<br>
<br>
runIdentity $ run $ enumList 10 [1..100] $ r $ joinI $ (map id $ r<br>
head) >> (map id $ r head)<br>
--> Right (Just 11)<br>
<br>
It is possible to fix this behavior, but it complicates the "obvious"<br>
definitions a lot.<br>
<br>
B<br>
<br>
On Wed, Sep 1, 2010 at 5:10 AM, Heinrich Apfelmus<br>
<<a href="mailto:apfelmus@quantentunnel.de">apfelmus@quantentunnel.de</a>> wrote:<br>
> Tilo Wiklund wrote:<br>
>><br>
>> Daniel Fischer wrote:<br>
>>><br>
>>> [...]<br>
>>> Well, I just gave an example where one would want chunking for reasons<br>
>>> other than performance. That iteratees don't provide the desired<br>
>>> functionality is a different matter.<br>
>>> [...]<br>
>><br>
>> In the case of hashing, wouldn't it be more reasonable to consider<br>
>> iterators over streams of fixed (or at least predictable) sized chunks<br>
>> (where a set of chunks can themselves be chunked), with the chunking<br>
>> behaviour being given by another iteratee over the original stream?<br>
>><br>
>> It seems to me that one of the major points of iteratees is to provide<br>
>> an abstraction from the kind of chunking irrelevant to the parsing<br>
>> logic, otherwise I fail to see any difference (at least relevant to<br>
>> chunking) to plain strict IO.<br>
><br>
> I thought so, too, but I was informed[1] that iteratees are just a small<br>
> step up the abstraction ladder. The difference compared to an ordinary file<br>
> Handle is that you can now reuse one and the same iteratee for reading<br>
> from a String , for instance, without changing the source code of the<br>
> iteratee.<br>
><br>
> Furthermore, iteratees can be suspended, which facilities resource<br>
> management like closing files handles after they've been read.<br>
><br>
> [1]:<br>
> <a href="http://www.reddit.com/r/haskell/comments/ar4wb/understanding_iteratees/c0j0f3r" target="_blank">http://www.reddit.com/r/haskell/comments/ar4wb/understanding_iteratees/c0j0f3r</a><br>
><br>
><br>
><br>
> Regards,<br>
> Heinrich Apfelmus<br>
><br>
> --<br>
> <a href="http://apfelmus.nfshost.com" target="_blank">http://apfelmus.nfshost.com</a><br>
><br>
> _______________________________________________<br>
> Haskell-Cafe mailing list<br>
> <a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
> <a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>
><br><br>
</blockquote></div><br>