开发者

How do you use the latest version (0.8.1.2 at time of writing) of the iteratee library?

I've read tutorials on the iteratee and enumerator concepts, and have implemented a sample version as a way of learning how they work. However, the types used in the iteratee package are very different than any of the tutorials I have found. For example, Iteratee is defined as:

Iteratee     
   runIter :: forall r. (a -> Stream s -> m r) 
           -> ((开发者_开发问答Stream s -> Iteratee s m a) 
           -> Maybe SomeException -> m r) 
           -> m r

I really don't understand what I am meant to do with that. Are there any tutorials on using this version, and why it was written this way (ie what benefits this has over the original way Oleg did it).


Disclaimer: I'm the current maintainer of iteratee.

You may find some of the files in the iteratee Examples directory useful for understanding how to use the library; word.hs is probably the easiest to follow.

Basically, users shouldn't need to use runIter unless you're creating custom enumeratees. Iteratees can be created by combining the provided primitives, and also with the liftI, idone, and icont functions, enumerated over, and then run with run or tryRun.

Oleg has two "original" versions and a CPS version (and possibly others too). The original versions are both in http://okmij.org/ftp/Haskell/Iteratee/IterateeM.hs. The first is the actual code, and the second is in the comments. The first requires some special functions, >>== and $$, in place of the usual >>= and $. The second can use the standard functions, but unfortunately it's very difficult to reason about monadic ordering with this version. There are a few other drawbacks as well. The CPS version avoids all of these issues, which is why I switched over iteratee. I also find that iteratees defined in this style are shorter and more readable. Unfortunately I'm not aware of any tutorials specific to the CPS version, however Oleg's comments may be useful.


Disclaimer: I don't know the iteratee much and have never used them. So take my answer with a grain of salt.

This definition is equivalent to Oleg's (more precisely, it's a CPS-style sum), with a twist: it guarantees that accessing the iteratee always return a monadic value.

Here is Oleg definition:

 data Iteratee el m a =
   | IE_done a
   | IE_cont (Maybe ErrMsg)
             (Stream el -> m (Iteratee el m a, Stream el))

So it's a sum of either done a, we're done a give a as a result, or cont (Maybe ErrMsg) (Stream el -> ...) : a way to continue the iteration given another chunk of input and, possibly an error (in which case continuing the continuation amounts to restarting the computation).

It is well-known that Either a b is equivalent to forall r. (a -> r) -> (b -> r) -> r : giving you either a or b is equivalent to promising you that, for any result r transform on a and transform of b you may come up with, I will be able to produce such an r (to do that I must have a a or a b). In a sense, (Either a b) introduces a data, and r. (a -> r) -> (b -> r) -> r eliminates this data: if such a function was named case_ab, then case_ab (\a -> foo_a) (\b -> foo_b) is equivalent to the pattern matching case ab of { Left a -> foo_a; Right b -> foo_b } for some ab :: Either a b.

So here is the continuation (we talk of continuations here because (a -> r) represents "what will happen of the value once we know it's an a") equivalent of Oleg's definition:

data Iteratee el m a =
  forall r.
    (a -> r) ->
    ((Maybe ErrMsg), (Stream el -> m (Iteratee el m a, Stream el)) -> r) ->
     r

But there is a twist in the iteratee definition (modulo some innocuous currying): the result is not r but m r: in a sense, we force the result of pattern matching on our iteratee to always live in the monad m.

data Iteratee el m a =
  forall r.
    (a -> m r) ->
    (Maybe ErrMsg -> (Stream el -> m (Iteratee el m a, Stream el)) -> m r) ->
     m r

Finally, notice that the "continuating the iteration" data in Oleg's definition is Stream .. -> m (Iterate .., Stream ..), while in the iteratee package it's only Stream -> Iteratee. I assume that they have removed the monad here because they enforce it at the outer level (if you apply the iteratee, you are forced to live in the monad, so why also force subsequent computation to live in the monad?). I don't know why there isn't the Stream output anymore, I suppose it means that those Iteratee have to consume all the input when it is available (or encode a "not finished yet" logic in the return type a). Perhaps this is for efficiency reasons.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜