
Hi Haskell cafe, Is there any standard or guideline for making a "partial" instance of a class, by which I mean implementing some methods of a class, but not all of them? In my concrete case I've got some type X which is almost an Arrow, except that I cannot lift any function a -> b to my type (of course I can for some a and b), so I cannot give a sensible implementation for arr. I can however give sensible implementations for the other methods in the Arrow class, and I'd like to use them (and possibly derived combinators) in other places. I see three possible solutions for this situation, I think I've seen at least the first two being used in well-known packages, but I couldn't find them anymore: 1. Make a class instance, and for the methods you don't implement put an 'error' call 2. Create functions with names from the class and with types specialised to your type, so that you can use it as if the instance was there. I.e. provide a function first :: X a b -> X (a, c) (b, c), which should be imported qualified to avoid name conflicts with the real Arrow class. The drawback of this is of course the conflicting names, but also the fact that derived combinators cannot be used. 3. Create functions with different names, to also avoid name clashes, i.e. firstX :: X a b -> X (a, c) (b, c). My preference would be to pick 1., but it feels quite bad in the same time. Any suggestions? Jeroen

Hi,
Is there any standard or guideline for making a "partial" instance of a class, by which I mean implementing some methods of a class, but not all of them? In my concrete case I've got some type X which is almost an Arrow, except that I cannot lift any function a -> b to my type (of course I can for some a and b), so I cannot give a sensible implementation for arr. I can however give sensible implementations for the other methods in the Arrow class, and I'd like to use them (and possibly derived combinators) in other places.
this might not be the general answer you're looking for, but related to this special case: Note that arrow syntax (both proc-do-notation and banana brackets) uses arr extensively under the hood. The same goes for many of the derived combinators. So you can not simply leave it out. But maybe there's no need to reinvent the wheel either. What you have probably is something like a /profunctor/ or a /braided category/, so you might be in luck finding some better suited library instead. For the former, probably the /profunctors/ https://hackage.haskell.org/package/profunctors library. For the latter, maybe the /subhask/ https://github.com/mikeizbicki/subhask prelude, but more likely the /categories/ https://hackage.haskell.org/package/categories library. If nothing else looking at them might help you better understand what structure you're dealing with. I personally don't use subhask, but the hierarchy diagrams and code snippets alone have been enlightening in the past. They might give you new search terms on the hunt for a better library. Or maybe it's enough to make it an /Applicative/? As a sidenote, I've seen this exact problem mentioned several times. Many nice things are almost arrows without an arr. But the arrow machinery pre-dates our current hierarchies and understanding, and it's never really been revised. From a more modern point of view there's little reason for its prominent place in base, except as an honorary member. There has also been discussion if/how the notation might be generalized. But it seems the pain was never strong enough, no one knows of a golden way forward, and there's always been ways around this. Oh well. Cheers, MarLinn

I would also like to register interest in what the community thinks about
this problem, and add a couple of more motivating examples that I face
regularly in my work:
1) `Bounded`, for things that have a minBound but no maxBound (like
String). I often resort to Default in this case to avoid the use of
`error`, but am unhappy with this because it doesn't "mean" the same thing,
nor can it use derived combinators, as Jeroen mentions.
2) `Enum`, when used with types with more than 2^64 values (i.e. a sha-256
derived "keyspace", with 2^256 values). The `fromEnum` documentation claims
"It is implementation-dependent what fromEnum returns when applied to a
value that is too large to fit in an Int", but since approximately zero
percent of 2^256 values will fit in an Int, I typically resort to `error`
for all cases just to make it clear that toEnum/fromEnum are not going to
work for any meaningful fraction of possible values.
Thanks!
-Rick
On Mon, Feb 26, 2018 at 11:36 AM, MarLinn
Hi,
Is there any standard or guideline for making a "partial" instance of a class, by which I mean implementing some methods of a class, but not all of them? In my concrete case I've got some type X which is almost an Arrow, except that I cannot lift any function a -> b to my type (of course I can for some a and b), so I cannot give a sensible implementation for arr. I can however give sensible implementations for the other methods in the Arrow class, and I'd like to use them (and possibly derived combinators) in other places.
this might not be the general answer you're looking for, but related to this special case:
Note that arrow syntax (both proc-do-notation and banana brackets) uses arr extensively under the hood. The same goes for many of the derived combinators. So you can not simply leave it out. But maybe there's no need to reinvent the wheel either. What you have probably is something like a *profunctor* or a *braided category*, so you might be in luck finding some better suited library instead. For the former, probably the *profunctors* https://hackage.haskell.org/package/profunctors library. For the latter, maybe the *subhask* https://github.com/mikeizbicki/subhask prelude, but more likely the *categories* https://hackage.haskell.org/package/categories library. If nothing else looking at them might help you better understand what structure you're dealing with. I personally don't use subhask, but the hierarchy diagrams and code snippets alone have been enlightening in the past. They might give you new search terms on the hunt for a better library.
Or maybe it's enough to make it an *Applicative*?
As a sidenote, I've seen this exact problem mentioned several times. Many nice things are almost arrows without an arr. But the arrow machinery pre-dates our current hierarchies and understanding, and it's never really been revised. From a more modern point of view there's little reason for its prominent place in base, except as an honorary member. There has also been discussion if/how the notation might be generalized. But it seems the pain was never strong enough, no one knows of a golden way forward, and there's always been ways around this. Oh well.
Cheers, MarLinn
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

To avoid the hellish nightmare of Java’s UnsupportedOperationException-riddled ecosystem, I think we should *very strongly* discourage partial implementations of typeclasses as much as humanly possible. If a type doesn’t fit the typeclass, please don’t pretend it does. If it turns out that our typeclasses are divided along bad semantic boundaries (which they clearly are in some cases), we should fix that instead of turning the typeclass landscape into a minefield. —Will

I’ve implemented a drop in replacement enum class here, which solves your
issue among other things:
https://hackage.haskell.org/package/generic-enum
If it doesn’t have some of the instances you require feel free to send me a
pull request.
On Tue, 27 Feb 2018 at 8:12 am, Will Yager
To avoid the hellish nightmare of Java’s UnsupportedOperationException-riddled ecosystem, I think we should *very strongly* discourage partial implementations of typeclasses as much as humanly possible. If a type doesn’t fit the typeclass, please don’t pretend it does.
If it turns out that our typeclasses are divided along bad semantic boundaries (which they clearly are in some cases), we should fix that instead of turning the typeclass landscape into a minefield.
—Will _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Also possibly interesting and relevant is Adam Megacz's fascinating (but
sadly abandoned) work on generalized arrows and hetmet programming:
http://www.megacz.com/berkeley/garrows/
On Mon, Feb 26, 2018 at 4:20 PM, Clinton Mead
I’ve implemented a drop in replacement enum class here, which solves your issue among other things:
https://hackage.haskell.org/package/generic-enum
If it doesn’t have some of the instances you require feel free to send me a pull request.
On Tue, 27 Feb 2018 at 8:12 am, Will Yager
wrote: To avoid the hellish nightmare of Java’s UnsupportedOperationException-riddled ecosystem, I think we should *very strongly* discourage partial implementations of typeclasses as much as humanly possible. If a type doesn’t fit the typeclass, please don’t pretend it does.
If it turns out that our typeclasses are divided along bad semantic boundaries (which they clearly are in some cases), we should fix that instead of turning the typeclass landscape into a minefield.
—Will _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Also check out my Freelude package which allows for the definition of
restricted arrows like you’ve mentioned:
https://hackage.haskell.org/package/freelude
On Tue, 27 Feb 2018 at 2:49 pm, Daniel Peebles
Also possibly interesting and relevant is Adam Megacz's fascinating (but sadly abandoned) work on generalized arrows and hetmet programming: http://www.megacz.com/berkeley/garrows/
On Mon, Feb 26, 2018 at 4:20 PM, Clinton Mead
wrote: I’ve implemented a drop in replacement enum class here, which solves your issue among other things:
https://hackage.haskell.org/package/generic-enum
If it doesn’t have some of the instances you require feel free to send me a pull request.
On Tue, 27 Feb 2018 at 8:12 am, Will Yager
wrote: To avoid the hellish nightmare of Java’s UnsupportedOperationException-riddled ecosystem, I think we should *very strongly* discourage partial implementations of typeclasses as much as humanly possible. If a type doesn’t fit the typeclass, please don’t pretend it does.
If it turns out that our typeclasses are divided along bad semantic boundaries (which they clearly are in some cases), we should fix that instead of turning the typeclass landscape into a minefield.
—Will _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Hi,
Is there any standard or guideline for making a "partial" instance of a class, by which I mean implementing some methods of a class, but not all of them? In my concrete case I've got some type X which is almost an Arrow, except that I cannot lift any function a -> b to my type (of course I can for some a and b), so I cannot give a sensible implementation for arr. I can however give sensible implementations for the other methods in the Arrow class, and I'd like to use them (and possibly derived combinators) in other places.
this might not be the general answer you're looking for, but related to this special case:
Note that arrow syntax (both proc-do-notation and banana brackets) uses arr extensively under the hood. The same goes for many of the derived combinators. So you can not simply leave it out. But maybe there's no need to reinvent the wheel either. What you have probably is something like a /profunctor/ or a /braided category/, so you might be in luck finding some better suited library instead. For the former, probably the /profunctors/ https://hackage.haskell.org/package/profunctors library. For the latter, maybe the /subhask/ https://github.com/mikeizbicki/subhask prelude, but more likely the /categories/ https://hackage.haskell.org/package/categories library. If nothing else looking at them might help you better understand what structure you're dealing with. I personally don't use subhask, but the hierarchy diagrams and code snippets alone have been enlightening in the past. They might give you new search terms on the hunt for a better library.
Perfect. In my concrete case I think a profunctor is indeed the thing I was looking for, and based on the other replies it seems that in general there are usually other classes that do match the set of functions you'd like. This of course doesn't completely solve the problem of the desire to use certain combinators, but I do agree that using error to partially implement a class isn't satisfactory either, and is very likely to lead to more problems. Jeroen

On Tue, Feb 27, 2018 at 11:38:21AM +0100, Jeroen Bransen wrote:
In my concrete case I think a profunctor is indeed the thing I was looking for
If you're willing to share your datatype I may be able to help determine exactly what sort of thing it is. I have extensively explored the place of profunctors :)

In my concrete case I think a profunctor is indeed the thing I was looking for If you're willing to share your datatype I may be able to help determine exactly what sort of thing it is. I have extensively explored the place of profunctors :) http://hackage.haskell.org/package/progress-reporting-1.1.0/docs/Control-Mon...
It's a class of functions (that may run in some monadic context) for which we can report progress. I can lift certain types of functions to this space (those that construct items of a list, or those that report their own progress in some way), and then these compose in several ways. Obviously having the first and second combinators from arrows comes in handy.

On Tue, Feb 27, 2018 at 12:02:49PM +0100, Jeroen Bransen wrote:
In my concrete case I think a profunctor is indeed the thing I was looking for If you're willing to share your datatype I may be able to help determine exactly what sort of thing it is. I have extensively explored the place of profunctors :) http://hackage.haskell.org/package/progress-reporting-1.1.0/docs/Control-Mon...
It's a class of functions (that may run in some monadic context) for which we can report progress. I can lift certain types of functions to this space (those that construct items of a list, or those that report their own progress in some way), and then these compose in several ways. Obviously having the first and second combinators from arrows comes in handy.
The type in question is WithProgress data WithProgress m a b where Id :: WithProgress m a a WithProgressM :: ((Double -> m ()) -> a -> m b) -> WithProgress m a b Combine :: WithProgress m b c -> WithProgress m a b -> WithProgress m a c SetWeight :: Double -> WithProgress m a b -> WithProgress m a b Is this definition of arr somehow unsatisfactory? arr :: Applicative m => (a -> b) -> WithProgress m a b arr f = WithProgressM (\_ a -> pure (f a)) NB that if you implement Category and Profunctor then you automatically get arr (\f -> lmap f id). Tom

On Tue, Feb 27, 2018 at 11:21:51AM +0000, Tom Ellis wrote:
NB that if you implement Category and Profunctor then you automatically get arr (\f -> lmap f id).
Or perhaps put more simply, you have no hope of making something an Arrow if you can't make it a Functor, but if you *do* have Functor and Category then you automatically get arr f = fmap f id Tom

On Mon, Feb 26, 2018 at 06:36:27PM +0100, MarLinn wrote:
I've got some type X which is almost an Arrow, except that I cannot lift any function a -> b to my type (of course I can for some a and b), so I cannot give a sensible implementation for arr. I can however give sensible implementations for the other methods in the Arrow class, and I'd like to use them (and possibly derived combinators) in other places.
[...]
... I've seen this exact problem mentioned several times. Many nice things are almost arrows without an arr. But the arrow machinery pre-dates our current hierarchies and understanding, and it's never really been revised.
There's a myth floating around that "Arrow is much less useful because it forces you to implement arr". In fact, Arrow without arr would be as useless as Applicative without fmap. In almost all situations where you are stymied by arr a small redesign will solve the whole problem. In fact, you need to get into the realm of linear-types-like things before arr is too much (and even then a *linear* arr would be fine). I designed a library for constructing Postgres queries and it uses an Arrow interface. https://hackage.haskell.org/package/opaleye-0.5.3.0/docs/Opaleye-Internal-Qu... Naturally there is no way to run an arbitrary Haskell function "in the database". This is not an impediment because everything that the database acts on inside the arrow type (QueryArr) is wrapped in an abstract type (Column). This means the only way that arbitrary Haskell functions can be used inside the arrow is as a sort of "partial compilation". There is, in effect, a staging restriction. Haskell functions a -> b run at "query compile time" and Postgres functions run at "query run time". This observation was made in an ICFP '13 paper in the context of our beloved monads so nothing that I'm saying here is particular to those inscrutable arrows. http://www.cse.chalmers.se/~joels/writing/bb.pdf I would be sad to think that Haskell programmers are avoiding using Arrow because of this myth[1]. If Jeroen Bransen or anyone else would like more details about this approach please get in touch either via this list or personally. I'm happy to help out. Tom [1] On the other hand, avoiding using Arrow because the type in question is actually a Monad is a perfectly good reason.

I was under the impression most programmers avoid Arrows because they've seen HXT. >.> Which really wants to be Applicative, not Arrow, so it's not the best example of Arrows out there. On Tue, Feb 27, 2018 at 5:52 AM, Tom Ellis < tom-lists-haskell-cafe-2013@jaguarpaw.co.uk> wrote:
On Mon, Feb 26, 2018 at 06:36:27PM +0100, MarLinn wrote:
I've got some type X which is almost an Arrow, except that I cannot lift any function a -> b to my type (of course I can for some a and b), so I cannot give a sensible implementation for arr. I can however give sensible implementations for the other methods in the Arrow class, and I'd like to use them (and possibly derived combinators) in other places.
[...]
... I've seen this exact problem mentioned several times. Many nice things are almost arrows without an arr. But the arrow machinery pre-dates our current hierarchies and understanding, and it's never really been revised.
There's a myth floating around that "Arrow is much less useful because it forces you to implement arr". In fact, Arrow without arr would be as useless as Applicative without fmap. In almost all situations where you are stymied by arr a small redesign will solve the whole problem. In fact, you need to get into the realm of linear-types-like things before arr is too much (and even then a *linear* arr would be fine).
I designed a library for constructing Postgres queries and it uses an Arrow interface.
https://hackage.haskell.org/package/opaleye-0.5.3.0/docs/ Opaleye-Internal-QueryArr.html
Naturally there is no way to run an arbitrary Haskell function "in the database". This is not an impediment because everything that the database acts on inside the arrow type (QueryArr) is wrapped in an abstract type (Column). This means the only way that arbitrary Haskell functions can be used inside the arrow is as a sort of "partial compilation". There is, in effect, a staging restriction. Haskell functions a -> b run at "query compile time" and Postgres functions run at "query run time".
This observation was made in an ICFP '13 paper in the context of our beloved monads so nothing that I'm saying here is particular to those inscrutable arrows.
http://www.cse.chalmers.se/~joels/writing/bb.pdf
I would be sad to think that Haskell programmers are avoiding using Arrow because of this myth[1]. If Jeroen Bransen or anyone else would like more details about this approach please get in touch either via this list or personally. I'm happy to help out.
Tom
[1] On the other hand, avoiding using Arrow because the type in question is actually a Monad is a perfectly good reason.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
-- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

Hi,
There's a myth floating around that "Arrow is much less useful because it forces you to implement arr". In fact, Arrow without arr would be as useless as Applicative without fmap. In almost all situations where you are stymied by arr a small redesign will solve the whole problem. In fact, you need to get into the realm of linear-types-like things before arr is too much (and even then a *linear* arr would be fine).
I designed a library for constructing Postgres queries and it uses an Arrow interface.
https://hackage.haskell.org/package/opaleye-0.5.3.0/docs/Opaleye-Internal-Qu...
Naturally there is no way to run an arbitrary Haskell function "in the database". This is not an impediment because everything that the database acts on inside the arrow type (QueryArr) is wrapped in an abstract type (Column). This means the only way that arbitrary Haskell functions can be used inside the arrow is as a sort of "partial compilation". There is, in effect, a staging restriction. Haskell functions a -> b run at "query compile time" and Postgres functions run at "query run time".
Hm. Interesting point. And a nice coincidence that you call Applicative without fmap "useless". I just recently saw one of those. It *did* feel like there might be a better structure, but I couldn't pin it down. Maybe your technique works in that context as well? Would you mind having a look? I'd like to have my eyes opened in that direction. The structure in question are XML-Picklers, i.e. tools to convert to and from XML. The original types are from HXT https://hackage.haskell.org/package/hxt-9.3.1.16/docs/src/Text-XML-HXT-Arrow..., but for the purpose of discussion we can simplify them to data PU a = PU { appPickle :: a -> XmlState -> XmlState -- turn a value into XML , appUnPickle :: XmlState -> (Either UnpickleErr a, XmlState) -- turn XML into a value } -- "pure" xpLift :: a -> PU a xpLift x = PU { appPickle = const id , appUnPickle = purex }-- Combine two picklers sequentially -- If the first fails during unpickling, the whole unpickler failsxpSeq :: (b -> a) -> PU a -> (a -> PU b) -> PU b xpSeq f pa k = PU { appPickle = ( \ b -> let a = f b in appPickle pa a . appPickle (k a) b ) , appUnPickle = appUnPickle pa >>= (appUnPickle . k) }-- Pickle a pair of values sequentially xpPair :: PU a -> PU b -> PU (a, b) xpPair pa pb = ( xpSeq fst pa (\ a -> xpSeq snd pb (\ b ->xpLift (a,b))) ) -- The closest equivalent to "fmap" xpWrap :: (a -> b, b -> a) -> PU a -> PU b Now: This is not exactly an Applicative. If it where a functor, it would be a (lax) monoidal functor. Taking syntax from the Typeclassopedia https://wiki.haskell.org/Typeclassopedia#Alternative_formulation, xpPair would be Monoidal's (**). And a (lax) monoidal functor is exactly an Applicative. If I'm not mistaken this structure satisfies all the laws of Monoidal – except that it is not a functor. Obviously there's no way to implement fmap because you always need to provide functions for both directions, as seen in xpWrap. So how would you change this structure to make it possible? It feels like the underlying problem is the same as with arr: At first there seems to be no way to lift functions into the structure. And we don't want to create two separate types because the whole idea of PU is to make pairs of related picklers and unpicklers composable. Do I have a blind eye, nourished by that myth that often lifting is not possible? Or did I stumble upon that one usecase where there IS a useful Applicative-without-fmap? MarLinn

On Tue, Feb 27, 2018 at 02:28:31PM +0100, MarLinn wrote:
There's a myth floating around that "Arrow is much less useful because it forces you to implement arr". In fact, Arrow without arr would be as useless as Applicative without fmap.
a nice coincidence that you call Applicative without fmap "useless". I just recently saw one of those. It *did* feel like there might be a better structure, but I couldn't pin it down. Maybe your technique works in that context as well? ...
The structure in question are XML-Picklers, i.e. tools to convert to and from XML. The original types are from HXT
https://hackage.haskell.org/package/hxt-9.3.1.16/docs/src/Text-XML-HXT-Arrow...
Obviously there's no way to implement fmap because you always need to provide functions for both directions .... So how would you change this structure to make it possible?
Observe the definition from the HXT source data PU a = PU { appPickle :: Pickler a , appUnPickle :: Unpickler a , theSchema :: Schema } type Pickler a = a -> St -> St newtype Unpickler a = UP { runUP :: St -> (UnpickleVal a, St) } type UnpickleVal a = Either UnpickleErr a Pickler is contravariant (Contravariant) and Unpickler is covariant (Functor) so if we slighly augment PU we get a Profunctor. data PU' a b = PU { appPickle :: Pickler a , appUnPickle :: Unpickler b , theSchema :: Schema } In fact Unpickler is a Monad (isomorphic to an EitherT of a State) so "PU' a" is an Applicative and PU is what I call a "product profunctor". https://hackage.haskell.org/package/product-profunctors This little augumentation in the definition of PU gets you a whole host of free functionality from the libaries for profunctors, applicatives and product profunctors. (By the way, this observation is completely different from the "compiling languages for different targets" technique that I mentioned in the previous post.) Tom

On Tue, Feb 27, 2018 at 01:46:49PM +0000, Tom Ellis wrote:
In fact Unpickler is a Monad (isomorphic to an EitherT of a State) so "PU' a" is an Applicative and PU is what I call a "product profunctor".
(Oh, we also need Pickler to be Data.Functor.Contravariant.Divisible, which it indeed is.)

In fact Unpickler is a Monad (isomorphic to an EitherT of a State) so "PU' a" is an Applicative and PU is what I call a "product profunctor".
https://hackage.haskell.org/package/product-profunctors
This little augumentation in the definition of PU gets you a whole host of free functionality from the libaries for profunctors, applicatives and product profunctors.
(By the way, this observation is completely different from the "compiling languages for different targets" technique that I mentioned in the previous post.)
I did see that I could turn PU into a profunctor, but not that that would make it an Applicative. Huh. Thanks for the tip! (I may have been distracted by looking for an arr to turn that profunctor into an arrow though.) It seems that while the particular observation is quite different, the more general approach is similar. Which nicely brings us back to the original question: If something "almost" fits a class, there's probably a better one around the corner. One might just be blind right now. Cheers, MarLinn

Not sure if everyone just missed my earlier link, but this talk of "Arrow
without arr is useless" seems odd in the face of significant academic work
(with Coq proofs, GHC extension, real-world use case for heterogeneous
metaprogramming, etc.) going into exactly that abstraction.
Here it is again, if you did miss it:
http://www.megacz.com/berkeley/garrows/
On Tue, Feb 27, 2018 at 9:19 AM, MarLinn
In fact Unpickler is a Monad (isomorphic to an EitherT of a State) so "PU'
a" is an Applicative and PU is what I call a "product profunctor".
https://hackage.haskell.org/package/product-profunctors
This little augumentation in the definition of PU gets you a whole host of free functionality from the libaries for profunctors, applicatives and product profunctors.
(By the way, this observation is completely different from the "compiling languages for different targets" technique that I mentioned in the previous post.)
I did see that I could turn PU into a profunctor, but not that that would make it an Applicative. Huh. Thanks for the tip! (I may have been distracted by looking for an arr to turn that profunctor into an arrow though.)
It seems that while the particular observation is quite different, the more general approach is similar. Which nicely brings us back to the original question: If something "almost" fits a class, there's probably a better one around the corner. One might just be blind right now.
Cheers, MarLinn
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

On Tue, Feb 27, 2018 at 10:15:04AM -0500, Daniel Peebles wrote:
Not sure if everyone just missed my earlier link, but this talk of "Arrow without arr is useless" seems odd in the face of significant academic work (with Coq proofs, GHC extension, real-world use case for heterogeneous metaprogramming, etc.) going into exactly that abstraction.
Here it is again, if you did miss it: http://www.megacz.com/berkeley/garrows/
I didn't say that "Arrow without arr is useless" I said it would be "as useless as Applicative without fmap". 99% of Haskell programmers would never consider complaining about Applicative because it requires fmap and the same ought to be true about Arrow and arr. The page you link to documents research which I'm sure has great merit. Unfortunately it also promotes the myth that I was trying to dispel. It claims Haskell Arrows support metaprogramming only when the guest language is a superset of Haskell, because every Haskell function can be promoted to a guest language expression using arr. but as both my Postgres library Opaleye and the paper I linked demonstrate this is not correct. Arrow can target languages that have no connection to Haskell. For the two concrete examples that have appeared on this list since my first message GArrow is not the appropriate solution. I invite readers to submit their own examples where it is. Tom

Hi,
On 27 February 2018 at 13:28, MarLinn
It feels like the underlying problem is the same as with arr: At first there seems to be no way to lift functions into the structure. And we don't want to create two separate types because the whole idea of PU is to make pairs of related picklers and unpicklers composable.
For my own learning, a while ago I implemented a little encoding/decoding library, with the encoders based on contravariant functors. I started with a type which I called `Codec a`, which contained both an encoding and a decoding function. As you did, I quickly found that this makes many typeclass instances impossible. So, like in Tom's reply, I instead added a more generic `Codec' a b` type, which separates the encoding and decoding parameters. I kept `Codec a` as a type synonym for `Codec' a a`. I found the change to make the resulting code much nicer to implement and to use, even though it would be possible for a user to construct an encoder/decoder pair which decodes to a different type than what they started with. In fact, after another round of type parameter introduction (abstracting over the concrete type of the encoded value: bytestrings and bytestring builders in `Codec'`, but type parameters in the yet more general type), I discovered a very natural separation between my "codecs" and combinators for composing them. So in this case, I suppose the moral of the story is that having a type parameter which is both covariant and contravariant is not that useful, and you can always just constrain the type variables to be the same where you need to anyway. The code is here: https://github.com/barrucadu/wheat -- Michael Walker (http://www.barrucadu.co.uk)
participants (9)
-
Brandon Allbery
-
Clinton Mead
-
Daniel Peebles
-
Jeroen Bransen
-
MarLinn
-
Michael Walker
-
Rick Owens
-
Tom Ellis
-
Will Yager