That's exactly right. `pipes-aeson` can take advantage of the
additional encoding information to provide full lenses, whereas parsers
in general cannot.
On 2/9/2014 8:33 AM, Pierre R wrote:
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
<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].
--
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].