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].
To post to this group, send email to [email protected].

--
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].

Reply via email to