Re: [Haskell-cafe] [ghc-proposals/cafe] Partially applied type families

On Tue May 30 19:43:30 UTC 2017, Richard Eisenberg wrote:
On May 24, 2017, at 3:13 AM, Anthony Clayden wrote:
... Some functions are defined by an ordered set of equations. Some (that is, class methods) are defined by an unordered set of equations, perhaps distributed across modules. Both models are useful.
Sure. Let a 100 schools of thought contend.
... [equality constraints and equality guards are] different, but I think the equality guard is useless
I agree adds nothing over repeating the typevar. And I've already agreed the potential for confusion with (~) constraints. So noted. I'll include it in the proposal, where a wider audience can bikeshed.
I see two main uses/benefits: 1. avoids the need for non-linear patterns in the head
Agreed that it would do this. But why is that important?
I was in part thinking of your wondering-out-loud earlier in the Partially applied thread https://mail.haskell.org/pipermail/haskell-cafe/2017-May/127078.html If we want to part-apply a type Fun which has a non-linear lhs, how does that go with your case-equation style? Adapting that earlier example:
type family F a b where F a a = () -- added an equation F Int b = b F a Bool = a
would really mean
type F a b = case a of _ -> case b of -- ?? _ match-all a -> () -- ?? re-using typevar a Int -> b _ -> case b of Bool -> a _ -> F a b
2. visually points up the 'non-apartness' vs an, um. "apartness guard"
(When I was figuring out Andy A-M's 2013 example, I rewrote the non-linear patterns with ~ guards, so I could figure out the apartness guards esp for the semi-apart instances. I posted the later workings to your blog
Somehow, this is more convincing. But I'm still not convinced on this point. Happily, you don't need to convince me -- put in the proposal what you like and then we can debate a concrete design.
[except as a type-level "let", I suppose].)
They would work as "let", I think:
instance Either a a | a ~ SomethingBigAndUgly where ...
Note that the `a` is not introduced in the guard.
Ah, OK. I get you. Equally that could be
instance Either a b | a ~ b, a ~ SomethingBigAndUgly where ..
Ok thanks, yes [TypeError] helps. Nevertheless it seems disergonomic to write an instance for a type-equal case, even with a helpful error message; when what you want is: no such instance.
You could always view
instance TypeError ... => C Int Bool
as sugar for
instance C Int Bool fails
Yes I understand that. But no I don't want any instance. (Sugar on rotten fruit doesn't hide the smell.) There are (or at least used to be) all sorts of side-effects from there in effect being an instance that matched.
What I can see will be awkward is backwards compatibility: can a class/type family with guards coexist with CTFs and with classes using overlap?
Sure. There would be no problem with this. The new idea is just that: new. I don't see it as getting rid of anything we already have. Perhaps some day we could think about removing OverlappingInstances, but we certainly don't have to do that at the same time as introducing instance guards. (I do like that name, too.)
OK. Perhaps you're seeing something I can't. To adapt your example from a parallel message, suppose:
module A
class {-# INSTANCEGUARDS #-} C a where ... instance C (Maybe a) | a /~ Int where ... instance C (Maybe Int) where ...
module B -- knows nothing of InstanceGuards import A
instance {-# OVERLAPPABLE #-} C (Maybe Bool) where ...
I want to reject that `(Maybe Bool)` instance. Even though it would legitimately be OVERLAPPABLE by (Maybe a) (that is, without the `a /~ Int` guard). Furthermore I might want a class to be InstanceGuarded, even though the instances I declare don't themselves need guards. (That is, I'm wanting to avoid 'future' overlaps in modules that import the class.)
I'll have a crack at the proposal.
Great. Thanks!
(Likely I'll need some help with the protocols.) AntC

On May 31, 2017, at 12:31 AM, Anthony Clayden
wrote: If we want to part-apply a type Fun which has a non-linear lhs, how does that go with your case-equation style?
Problematically. This is why my thesis muses on -- but stops well short of solving -- the problem of non-linear patterns. I'm not sure how it all fits together.
You could always view
instance TypeError ... => C Int Bool
as sugar for
instance C Int Bool fails
Yes I understand that. But no I don't want any instance. (Sugar on rotten fruit doesn't hide the smell.)
I hereby pronounce
instance TypeError ... => C Int Bool
as "not an instance". In other words, I'm not sure what you're getting at here other than concrete syntax. How does not having an instance differ than the TypeError solution?
OK. Perhaps you're seeing something I can't. To adapt your example from a parallel message, suppose: <snip>
What you're getting at here is that there may be interesting interplay between instance guards and OverlappingInstances. Indeed. This would have to be worked out (or left as an open question) in the proposal. Regardless, I think that hashing out this level of detail here is the wrong place. Put it in the proposal! That way, the ensuing debate involves more of the community and persists better. Richard
participants (2)
-
Anthony Clayden
-
Richard Eisenberg