love-haskell / coercible-utils

Utility functions for Coercible types
https://hackage.haskell.org/package/coercible-utils
BSD 3-Clause "New" or "Revised" License
9 stars 3 forks source link

addition of coercive composition #1

Closed chessai closed 6 years ago

chessai commented 6 years ago

Would the following be within the scope of this library?:

-- | Coercive left-composition.
infixr 9 #.
(#.) :: Coercible b c => (b -> c) -> (a -> b) -> a -> c
(#.) _ = coerce
{-# INLINE (#.) #-}

-- | Coercive right-composition.
infixr 9 .#
(.#) :: Coercible a b => (b -> c) -> (a -> b) -> a -> c
(.#) f _ = coerce f
{-# INLINE (.#) #-}

These can be especially handy, due to problems expressed in GHC Trac #7542. To quote the note in Data.Functor.Utils (in base):

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

chessai commented 6 years ago

If this isn't in the scope of the library, you can just let me know and close the issue

sjakobi commented 6 years ago

Thanks, these functions look very on-topic for a library named coercible-utils. :)

Care to make a PR!? :)

Just in case you aren't aware, you can already find these functions in Data.Profunctor.Unsafe.

chessai commented 6 years ago

Just in case you aren't aware, you can already find these functions in Data.Profunctor.Unsafe.

Ah, yes, Edward Kmett brought this to my attention when I asked on the libraries mailing list that #. and .# be exported somewhere from base, since I noticed that some internal modules in base contain some useful functions.

Here is the mailing list issue: https://mail.haskell.org/pipermail/libraries/2018-April/028725.html