tag:blogger.com,1999:blog-1777990983847811806.post2413465613006075645..comments2020-01-17T07:55:53.619-08:00Comments on Haskell for all: Haskell for Purists - Pipe FinalizationGabriel Gonzalezhttp://www.blogger.com/profile/01917800488530923694noreply@blogger.comBlogger3125tag:blogger.com,1999:blog-1777990983847811806.post-39911448379511616952012-04-27T14:10:35.951-07:002012-04-27T14:10:35.951-07:00Thanks very much! I'll read issue 19 & thi...Thanks very much! I'll read issue 19 & think about the other stuff!myzoskihttps://www.blogger.com/profile/02622704681931775367noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-18510241099351201372012-04-27T13:20:58.624-07:002012-04-27T13:20:58.624-07:00So for your first question, the answer to your que...So for your first question, the answer to your question is that the whole finalizer solution is actually much much more general than just finalizers. It can be applied to anything that is a monoid. A finalizer is just a specific kind of monoid (where mempty is return () and mappend just sequences two finalizers). If you think of each pipe as having an associated monoid element (registered by catchH or by manually yielding the monoid element), then the pipeline is like a list of monoids and all that the Heap category is doing is doing mconcat over all the upstream pipes to combine them into a single monoid element.<br /><br />So one thing I've been considering is extending heap to just include the monoid in the return value instead of running it (which only makes sense for finalizers). This means you can then truly generalize heap to work with any monoid and not just finalizers. Then what you would do is make your monoid the pair of monoids:<br /><br />(Finalizer m, UnconsumedInput)<br />-- Note, a pair of monoids is a monoid itself<br /><br />where mempty for UnconsumedInput is no dangling input and mappend combines multiple unconsumed inputs. Because this is a monoid fold over the entire pipeline, you can actually register unconsumed inputs from EVERY pipe in the pipeline, not just that one single pipe, and ensure they all get delivered in the final return value (assuming you come up with a sensible way to mappend them all together).<br /><br />Then your composite pipe's return value includes both the finalizer monoid and the unresolved input monoid and you do whatever you want with them.<br /><br />To answer your second question, there are some implementations of free monad transformers on Hackage, but they are not recognized as such. You can find my implementation here:<br /><br />https://github.com/Gabriel439/Haskell-Pipes-Library/blob/master/Control/Monad/Trans/Free.hs<br /><br />The latest patch of the library actually formulates Pipes as free monad transformers, which you can see here:<br /><br />https://github.com/Gabriel439/Haskell-Pipes-Library/blob/master/Control/Pipe/Common.hs<br /><br />If you want a good idea of what free monad transformers are good for, I highly recommend you read Issue 19 of the Monad Reader, which you can find here:<br /><br />http://themonadreader.files.wordpress.com/2011/10/issue19.pdf<br /><br />The article in that issue on concurrency by Mario Blazevic basically walks you through various uses of a free monad transformer, but in his article he calls it the "Coroutine" type.<br /><br />Like you mentioned, a correct MonadTrans instance requires at least one pass through the base monad at a minimum and until we have a perfect compiler then binds are not free. However, I've actually done some quick and dirty benchmarks of pipes code and I find that it causes a negligible difference in performance, with only about a 1% decrease in speed for the simple cases I tried out.<br /><br />Also, your refactorization of pipes to correct MonadTrans is correct and it's isomorphic to the implementation I have in my latest patch. I highly recommend you learn about free monads first, and then "free monad transformers" are just the monad transformer version of the "free monad". A free monad is a very useful concept to learn and it simplifies a lot of programs.Gabriel Gonzalezhttps://www.blogger.com/profile/01917800488530923694noreply@blogger.comtag:blogger.com,1999:blog-1777990983847811806.post-62604400487774661252012-04-27T12:55:51.305-07:002012-04-27T12:55:51.305-07:00Hi Gabriel,
Thanks for this great stuff!
A coupl...Hi Gabriel,<br /><br />Thanks for this great stuff!<br /><br />A couple of questions. The first one is practical.<br />Suppose I have a pipeline, say a producer that reads a file and yields bytestrings, an intermediate stage that awaits bytestrings and yields Chars, and a stage that awaits Chars, accumulating them until a token separator, and yields tokens (e.g. identifiers) downstream. There is a little problem though, if the upstream producer hits an end-of-file and terminates; there may be an identifier in progress (properly ended by the EOF, according to allowed syntax) in the token stage that doesn't get yielded downstream because the whole pipeline has terminated.<br /><br />Is there a nice way to deal with this sort of case?<br />I can think of some ad-hoc methods, passing Maybe's or<br />Either's through the whole pipe instead of Bytestrings and Chars, with the exceptional case encoding EOF, and using an additional 'yield Nothing' after the producer to indicate the EOF, but it doesn't immediately strike me as very attractive.<br /><br />A second question, not much related. I was trying to work through some proofs of the Monad / MonadTrans / Category laws in the pipes 1.0.2 library and ran into trouble with MonadTrans. I read in your article that you plan to change the MonadTrans instance. I'm fairly new to Haskell and don't know 'free monad transformers' yet. However, I thought I would try on my own; I came up with the following, but I'm worried that it seems to involve the base monad more than the original Pipes implementation and may not be as efficient. (Also, I haven't quite been able to prove transitivity yet, although some signs look promising to me; and I don't really know how to deal with bottoms and non-well-founded values like idP in inductive proofs, so I may well have proved even less than I think.)<br /><br /><a href="http://hpaste.org/67732" rel="nofollow">http://hpaste.org/67732</a>myzoskihttps://www.blogger.com/profile/02622704681931775367noreply@blogger.com