[Haskell-cafe] Is UndecidableInstances unavoidable in heterogenous Show derivation?
Viktor Dukhovni
ietf-dane at dukhovni.org
Sun Dec 1 04:06:00 UTC 2019
On Sun, Dec 01, 2019 at 03:36:58PM +1300, Anthony Clayden wrote:
> > ... was mildly surprised by the need for -XUndecidableInstances when
> > deriving the 'Show' instance for the heterogenous N-ary product
> > 'NP':
>
> There's been much debate: should we find a less scary name?
Perhaps, though the old name would have to stick around as an alias for
a few major releases. But if the idea is to discourage the use of the
extension when not essential, it's working! :-)
> Presumably your program compiles and runs OK with that switched on(?)
Yes.
> > I guess I should also ask whether there's a way to define something
> > equivalent to 'Compose' without 'UndecidableSuperClasses', and
> > perhaps the two are not unrelated.
>
> Not exactly related, but again superclass instance resolution wants to
> make the problem smaller at each step. The definition for class
> Compose has a constraint no smaller than the class head (3 variables).
What surprises me about 'Compose' is that it is not really trying to
define a class as such, rather it aims to construct a new constraint
(family) from an existing one. The definition feels like a subtle hack,
used only for lack of a more natural syntax:
http://hackage.haskell.org/package/type-combinators-0.2.4.3/docs/src/Type-Family-Constraint.html#Comp
class d (c a) => Comp (d :: l -> Constraint) (c :: k -> l) (a :: k)
instance d (c a) => Comp d c a
I'd have expected instead something more akin to:
type family Comp2 (c :: l -> Constraint) (f :: k -> l) :: k -> Constraint where
Comp2 c f = \x -> c (f x) -- Oops, no type-level lambdas
-- or
Comp2 c f x = c (f x) -- Oops, too many LHS parameters
but there seems to be no direct way to express this type of composite
constraint, without inventing the clever paired class and instance.
While I can write:
type family Comp2 (c :: l -> Constraint) (f :: k -> l) (x :: k) :: Constraint where
Comp2 c f x = c (f x)
And partial application of Comp2 even has the expected kind:
λ> :k Comp2 Show (K Int)
Comp2 Show (K Int) :: k -> Constraint
sadly, one can't actually use "Comp2 Show f":
λ> deriving instance All (Comp2 Show f) xs => Show (NP f xs)
• The type family ‘Comp2’ should have 3 arguments, but has been given 2
• In the context: All (Comp2 Show f) xs
While checking an instance declaration
In the stand-alone deriving instance for
‘All (Comp2 Show f) xs => Show (NP f xs)’
So the class/instance pair seems to be the only way.
> Yes that's a sensible policy. The trouble with -XUndecidableInstances
> is that it's a module-wide setting, so lifts the check for all
> instances of all classes.
So it seems best to isolate the code that needs this in as a small
module as possible, and do without everywhere else.
--
Viktor.
More information about the Haskell-Cafe
mailing list