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