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