Thanks that clears things up. I immediately didn't recognize the Getter in
parsed :: (Monad m, ParserInput a) => Attoparsec.Parser a b -- ^ Attoparsec parser -> Producer a m r -- ^ Raw input -> Producer b m (Either (ParsingError, Producer a m r) r) So if I get this right, it is not good to have `Lens'` in `pipes-attoparsec` because it is not clear the transformation is reversible for each `attoparsec` parsers but it would be nice to have one for the specific `json'` parser in `pipes-aeson`. On Sunday, February 9, 2014 2:51:09 PM UTC+1, Gabriel Gonzalez wrote: > > So there are two uses of lenses in the `pipes` ecosystem: `pipes-parse` > and `pipes-group` (i.e. the `FreeT` stuff). What I was referring to was > the use of lenses in `pipes-group`. The rough rule of thumb for when to > use lenses in `pipes-group` is: pretty much always (i.e. every "splitter" > should be a lens). > > I can also answer your question about when to use lenses in `pipes-parse`, > too. The answer is: if the transformation is reversible, make it a lens. > If the transformation is not reversible, make it a function between > `Producer`s (i.e. a "Getter", which is what it's isomorphic to). > > This is why `pipes-parse` is nothing but "Getter"s: none of the > transformations are reversible. > > To learn more about this last point, read the `pipes-parse` tutorial, > particularly the section on `Getter`s: > > > http://hackage.haskell.org/package/pipes-parse-3.0.1/docs/Pipes-Parse-Tutorial.html#g:4 > > On 02/09/2014 05:01 PM, Pierre R wrote: > > Is there any documentation about when it is not a good idea to define > `lens` ? > > I am thinking about `pipes-attoparsec` that has chosen not to define any. > > I know there is a thread that talk about this. It might be nice to > document this kind of argument. > > If `lens` is not always the best approach (even for skilled lens users), > then I would move them in a separated module as Renzo suggested (such as > `Pipes.Parse.Lens` and I would document the pro and cons there) > > On Saturday, February 8, 2014 5:04:01 PM UTC+1, Gabriel Gonzalez wrote: >> >> I got a couple of confused users upon the update to the lens-based API, >> mainly because it wasn't obvious to them how lenses worked and how to >> use `view` to turn a `Lens a b` into `a -> b`. For example, they didn't >> realize that they could get back the original `decodeGetMany` by using >> `view decodeGetL`. >> >> So I wanted to ask if there were any objections to me adding >> unidirectional non-lens versions of several lenses. I think the easiest >> way to explain what I mean is to just give a few examples. Take >> `Pipes.Parse.groupBy`, for example: >> >> groupBy >> :: Monad m >> => (a -> a -> Bool) >> -> Lens' (Producer a m x) (Producer a m (Producer a m x)) >> groupBy equals k p0 = fmap join (k (to p0)) >> where >> -- to :: Monad m => Producer a m r -> Producer a m (Producer a m x) >> to p = do >> x <- lift (next p) >> case x of >> Left r -> return (return r) >> Right (a, p') -> (yield a >> p') ^. span (equals a) >> >> I'd probably take the internal `to` function and promote it to a >> top-level exported function, named `groupBy_`: >> >> groupBy_ :: Monad m => (a -> a -> Bool) -> Producer a m x -> >> Producer a m (Producer a m x) >> groupBy_ equals p = ... >> >> Then define the `groupBy` lens in terms of `groupBy_`: >> >> groupBy equals k p = fmap join (k (groupBy_ p)) >> >> Another example is the `lines` function from `Pipes.ByteString`: >> >> lines >> :: Monad m >> => Iso' (Producer ByteString m x) (FreeT (Producer ByteString >> m) m x) >> lines = Data.Profunctor.dimap _lines (fmap _unlines) >> where >> -- _lines >> -- :: Monad m >> -- => Producer ByteString m x -> FreeT (Producer ByteString >> m) m x >> _lines p0 = PG.FreeT (go0 p0) >> where >> go0 p = do >> x <- next p >> case x of >> Left r -> return (PG.Pure r) >> Right (bs, p') -> >> if (BS.null bs) >> then go0 p' >> else return $ PG.Free $ go1 (yield bs >> p') >> go1 p = do >> p' <- p^.line >> return $ PG.FreeT $ do >> x <- nextByte p' >> case x of >> Left r -> return (PG.Pure r) >> Right (_, p'') -> go0 p'' >> >> -- _unlines >> -- :: Monad m >> -- => FreeT (Producer ByteString m) m x -> Producer >> ByteString m x >> _unlines = concats . PG.maps addNewline >> >> -- addNewline >> -- :: Monad m => Producer ByteString m r -> Producer >> ByteString m r >> addNewline p = p <* yield (BS.singleton nl) >> >> I'd promote `_lines` and `_unlines` to top-level exported functions, >> except I would change the names to `lines_` and `unlines_`: >> >> lines_ :: Monad m => Producer ByteString m x -> FreeT (Producer >> ByteString m) m x >> >> unlines_ :: Monad m => FreeT (Producer ByteString m) m x -> >> Producer ByteString m x >> >> ... and define the `lines` lens in terms of them: >> >> lines = Data.Profunctor.dimap lines_ (fmap unlines_) >> >> So I would still be keeping the lenses and isomorphisms, but also adding >> unidirectional non-lens equivalents to give beginners an easier >> toe-hold. What do you all think? >> > -- > You received this message because you are subscribed to the Google Groups > "Haskell Pipes" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected] <javascript:>. > To post to this group, send email to [email protected]<javascript:> > . > > > -- You received this message because you are subscribed to the Google Groups "Haskell Pipes" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected].
