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

Anthony Clayden anthony_clayden at clear.net.nz
Wed May 31 04:31:30 UTC 2017


> 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


More information about the Haskell-Cafe mailing list