core-libraries-committee
core-libraries-committee copied to clipboard
Representation-polymorphic `flip`
In the same vein as #132 and #158, I'd like to make flip representation-polymorphic:
flip :: forall r a b (c :: TYPE r). (a -> b -> c) -> b -> a -> c
flip f x y = f y x
This would allow, for instance, to define (&) = flip id without compromising its representational polymorphism.
This is a breaking change, as the current type application order for flip is:
flip @a @b @c :: (a -> b -> c) -> (b -> a -> c)
My vote will be -1, similar to https://github.com/haskell/core-libraries-committee/issues/132#issuecomment-1485331648 and https://github.com/haskell/core-libraries-committee/issues/158#issuecomment-1538458756.
Unfortunately the same fact eluded me in #158!
Should it maybe be
flip :: forall {r} a b (c :: TYPE r). (a -> b -> c) -> b -> a -> c
flip f x y = f y x
to prevent this from being a breaking change?
@mixphix thanks for noticing it. I think it's exceedingly rare to use visible type applications with flip, because one would be better off to specify type of flip's argument. But I'll prepare an impact assessment to be sure.
@sjoerdvisscher that's a good idea, I keep forgetting about the curly syntax. OTOH it would be not consistent with the current definitions of ($) and (&).
It's probably a good rule of thumb to use curly braces on all type arguments that can be inferred from the kinds of other type arguments. The types of ($) and (&) really should be changed too in my opinion.
This isn't just levity polymorphic, right? It's polymorphic over all representations. I think a levity polymorphic flip would be more restrictive:
flip :: forall (lev :: Levity) a b (c :: TYPE (BoxedRep lev)). (a -> b -> c) -> b -> a -> c
flip f x y = f y x
It's probably a good rule of thumb to use curly braces on all type arguments that can be inferred from the kinds of other type arguments.
I slightly disagree. As GHC doesn't give a way to explicitly apply curly type arguments, it's not an easy choice when designing the API. Not being able to explicitly type apply can be quite annoying when you really need that.
I agree with @phadej. Having an argument which is impossible to supply manually is actually extremely annoying in some cases.
This isn't just levity polymorphic, right? It's polymorphic over all representations.
You are right, let me update the title.
Given that there was no backlash for representational polymorphism changes to ($) and (&) and there are zero known examples of breakage, I'd rather keep things explicit and pursue for flip :: forall r a b (c :: TYPE r). ... without curly braces. I have to prepare an impact assessment though.
I've updated the proposal. The impact assessment did not reveal anything, so I believe it is good to go without "curly braces" contraption.
If there are no further comments, I'll trigger a vote soon.
Dear CLC members, let's vote on the proposal to make flip representation-polymorphic, so that the return value is not limited to lifted data:
flip :: forall repc a b (c :: TYPE repc). (a -> b -> c) -> b -> a -> c
flip f x y = f y x
The change is a continuation of earlier proposals #132 and #158 and aims to make flip more consistent with ($) and (&). The impact assessment did not reveal any breakage.
@hasufell @mixphix @velveteer @angerman @parsonsmatt @tomjaguarpaw
+1 from me, unsuprisingly.
-1
as per https://github.com/haskell/core-libraries-committee/issues/245#issuecomment-1949244983
+1
+1
@velveteer @angerman @parsonsmatt just a gentle reminder to vote.
+1
Thanks all, that's enough votes to approve.