(#.) :: Coercible b c => (b -> c) -> (a -> b) -> (a -> c)
(#.) _ = coerce {-# INLINE (#.) #-} (.#) :: Coercible a b => (b -> c) -> (a -> b) -> (a -> c) (.#) f _ = coerce f {-# INLINE (.#) #-} The first of these is exported from Data.Functor.Util, and used in many places inside of base for efficiency over '.' (compose), However no module in base actually exports these. I have recently been using Data.Coerce more frequently and think it would be useful to go ahead and export these from somewhere in base. For convenience, I will paste the note about (#.) from Data.Functor.Util: "Note [Function coercion] ~~~~~~~~~~~~~~~~~~~~~~~ Several functions here use (#.) instead of (.) to avoid potential efficiency problems relating to #7542. The problem, in a nutshell: If N is a newtype constructor, then N x will always have the same representation as x (something similar applies for a newtype deconstructor). However, if f is a function, N . f = \x -> N (f x) This looks almost the same as f, but the eta expansion lifts it--the lhs could be _|_, but the rhs never is. This can lead to very inefficient code. Thus we steal a technique from Shachaf and Edward Kmett and adapt it to the current (rather clean) setting. Instead of using N . f, we use N #. f, which is just coerce f `asTypeOf` (N . f) That is, we just *pretend* that f has the right type, and thanks to the safety of coerce, the type checker guarantees that nothing really goes wrong. We still have to be a bit careful, though: remember that #. completely ignores the *value* of its left operand. " _______________________________________________ Libraries mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries |
That seems useful indeed! Using only 'coerce' requires too many type
annotations. Would it make sense to generalize the type so it's clear that one argument is unused? (#.) :: Coercible b c => p b c -> (a -> b) -> (a -> c) (.#) :: Coercible a b => (b -> c) -> p a b -> (a -> c) Li-yao On 04/20/2018 03:56 PM, Daniel Cartwright wrote: > (#.) :: Coercible b c => (b -> c) -> (a -> b) -> (a -> c) > (#.) _ = coerce > {-# INLINE (#.) #-} > > (.#) :: Coercible a b => (b -> c) -> (a -> b) -> (a -> c) > (.#) f _ = coerce f > {-# INLINE (.#) #-} > > The first of these is exported from Data.Functor.Util, and used in many > places inside of base for efficiency over '.' (compose), However no module > in base actually exports these. I have recently been using Data.Coerce more > frequently and think it would be useful to go ahead and export these from > somewhere in base. > > For convenience, I will paste the note about (#.) from Data.Functor.Util: > > "Note [Function coercion] > ~~~~~~~~~~~~~~~~~~~~~~~ > > Several functions here use (#.) instead of (.) to avoid potential efficiency > problems relating to #7542. The problem, in a nutshell: > > If N is a newtype constructor, then N x will always have the same > representation as x (something similar applies for a newtype deconstructor). > However, if f is a function, > > N . f = \x -> N (f x) > > This looks almost the same as f, but the eta expansion lifts it--the lhs > could > be _|_, but the rhs never is. This can lead to very inefficient code. Thus > we > steal a technique from Shachaf and Edward Kmett and adapt it to the current > (rather clean) setting. Instead of using N . f, we use N #. f, which is > just > > coerce f `asTypeOf` (N . f) > > That is, we just *pretend* that f has the right type, and thanks to the > safety > of coerce, the type checker guarantees that nothing really goes wrong. We > still > have to be a bit careful, though: remember that #. completely ignores the > *value* of its left operand. > " > -------------- next part -------------- > An HTML attachment was scrubbed... > URL: <http://mail.haskell.org/pipermail/libraries/attachments/20180420/c5646504/attachment-0001.html> > Libraries mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries |
Generalizing the type like that helps a lot. I had skimmed the documentation before, but I didn’t immediately comprehend what it meant. When I read the type signatures you gave them, it immediately made sense.
Also, +1 on exporting these. Sent from my iPhone > On Apr 21, 2018, at 10:06 AM, Li-yao Xia <[hidden email]> wrote: > > That seems useful indeed! Using only 'coerce' requires too many type annotations. > > Would it make sense to generalize the type so it's clear that one argument is unused? > > (#.) :: Coercible b c => p b c -> (a -> b) -> (a -> c) > (.#) :: Coercible a b => (b -> c) -> p a b -> (a -> c) > > Li-yao > >> On 04/20/2018 03:56 PM, Daniel Cartwright wrote: >> (#.) :: Coercible b c => (b -> c) -> (a -> b) -> (a -> c) >> (#.) _ = coerce >> {-# INLINE (#.) #-} >> (.#) :: Coercible a b => (b -> c) -> (a -> b) -> (a -> c) >> (.#) f _ = coerce f >> {-# INLINE (.#) #-} >> The first of these is exported from Data.Functor.Util, and used in many >> places inside of base for efficiency over '.' (compose), However no module >> in base actually exports these. I have recently been using Data.Coerce more >> frequently and think it would be useful to go ahead and export these from >> somewhere in base. >> For convenience, I will paste the note about (#.) from Data.Functor.Util: >> "Note [Function coercion] >> ~~~~~~~~~~~~~~~~~~~~~~~ >> Several functions here use (#.) instead of (.) to avoid potential efficiency >> problems relating to #7542. The problem, in a nutshell: >> If N is a newtype constructor, then N x will always have the same >> representation as x (something similar applies for a newtype deconstructor). >> However, if f is a function, >> N . f = \x -> N (f x) >> This looks almost the same as f, but the eta expansion lifts it--the lhs >> could >> be _|_, but the rhs never is. This can lead to very inefficient code. Thus >> we >> steal a technique from Shachaf and Edward Kmett and adapt it to the current >> (rather clean) setting. Instead of using N . f, we use N #. f, which is >> just >> coerce f `asTypeOf` (N . f) >> That is, we just *pretend* that f has the right type, and thanks to the >> safety >> of coerce, the type checker guarantees that nothing really goes wrong. We >> still >> have to be a bit careful, though: remember that #. completely ignores the >> *value* of its left operand. >> " >> -------------- next part -------------- >> An HTML attachment was scrubbed... >> URL: <http://mail.haskell.org/pipermail/libraries/attachments/20180420/c5646504/attachment-0001.html> > _______________________________________________ > Libraries mailing list > [hidden email] > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries Libraries mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries |
Note: this way of indicating which argument is unused means that this confusingly looks almost precisely backwards relative to the more general code that created those names and usage pattern in the first place. (I don't have a particularly strong objection to allowing the same sort of tweak to that code, assuming type inference works out in practice for the major consumers of the combinators there. I don't really foresee a problem, but I've been surprised by interactions before.) I do have some concern that exporting these incompatible versions from Data.Coerce would break a subset of the code that is using the more general combinators in profunctors. e.g. in the lens library these were coined for the code for prisms imports both. This is why they were placed in a more obscure internal location to begin with as just the special case was needed by base and it was easier to write a copy locally than merge Profunctor to base. -Edward On Sat, Apr 21, 2018 at 10:16 AM, Andrew Martin <[hidden email]> wrote: Generalizing the type like that helps a lot. I had skimmed the documentation before, but I didn’t immediately comprehend what it meant. When I read the type signatures you gave them, it immediately made sense. _______________________________________________ Libraries mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries |
I don't personally think the slightly confusing appearance is worth worrying about. If inference works out, I like Li-yao's approach a lot. On Apr 21, 2018 7:27 PM, "Edward Kmett" <[hidden email]> wrote:
_______________________________________________ Libraries mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries |
In reply to this post by Daniel Cartwright
Hi,
Am Freitag, den 20.04.2018, 15:56 -0400 schrieb Daniel Cartwright: > I have recently been using Data.Coerce more frequently and think it > would be useful to go ahead and export these from somewhere in base. I expect the target audience of these functions to be pretty small (they need to know what coerce does, they need to care and know about the problem with composing newtype constructors with functions etc.) I don’t think any of these will struggle to define their (#.) locally – or simply call coerce directly on `f`, without specifying the unused newtype constructor. I am, however, worried about people who are not the target audience to see these operators and shoot in their foot with them (e.g. passing a function that “does something” as the first argument to #. and then being very confused that things don’t work.). The benefits don’t obviously outweigh the risks, so a mild hesitant -1 from me. Cheers, Joachim -- Joachim “nomeata” Breitner [hidden email] https://www.joachim-breitner.de/ _______________________________________________ Libraries mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries signature.asc (849 bytes) Download Attachment |
In reply to this post by David Feuer
It looks like inference works out. I've hacked up profunctors HEAD in a similar manner and pre-emptively narrowed my Data.Coerce imports there in case we do decide to export these from a more common location. I did have to drop support for ghc < 7.8 to get the more general signatures to work out nicely though, as the old default definitions aren't valid there afterwards. -Edward On Sat, Apr 21, 2018 at 7:44 PM, David Feuer <[hidden email]> wrote:
_______________________________________________ Libraries mailing list [hidden email] http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries |
Free forum by Nabble | Edit this page |