[GHC] #11523: Infinite Loop when mixing UndecidableSuperClasses and the class/instance constraint synonym trick.
GHC
ghc-devs at haskell.org
Mon Feb 1 18:36:01 UTC 2016
#11523: Infinite Loop when mixing UndecidableSuperClasses and the class/instance
constraint synonym trick.
-------------------------------------+-------------------------------------
Reporter: ekmett | Owner:
Type: bug | Status: new
Priority: highest | Milestone: 8.0.1
Component: Compiler | Version: 7.10.3
(Type checker) |
Keywords: | Operating System: Unknown/Multiple
UndecidableSuperClasses |
Architecture: | Type of failure: GHC rejects
Unknown/Multiple | valid program
Test Case: | Blocked By:
Blocking: | Related Tickets: #11480
Differential Rev(s): | Wiki Page:
-------------------------------------+-------------------------------------
There seems to be a bad interaction between `UndecidableSuperClasses` and
the common trick of using a cyclic definition of a class and instance to
make an alias at the constraint level:
{{{#!hs
class (Foo f, Bar f) => Baz f
instance (Foo f, Bar f) => Baz f
}}}
Unfortunately, there are circumstances in which you can't eliminate it,
such as
{{{#!hs
class (p, q) => p & q
instance (p, q) => p & q
}}}
There we can't partially apply (,) at the constraint level, but we can
talk about `(&) :: Constraint -> Constraint -> Constraint` and `(&) (Eq a)
:: Constraint -> Constraint`.
This doesn't seem to happen on simpler examples like the above, but once I
modify the categories example from #11480 to move the domain and codomain
of a functor into class associated types, so that they don't infect every
single subclass of functor, we run into a problem. The following stripped
down version of the code seems to send the compiler into an infinite loop:
{{{#!hs
{-# language KindSignatures #-}
{-# language PolyKinds #-}
{-# language DataKinds #-}
{-# language TypeFamilies #-}
{-# language RankNTypes #-}
{-# language NoImplicitPrelude #-}
{-# language FlexibleContexts #-}
{-# language MultiParamTypeClasses #-}
{-# language GADTs #-}
{-# language ConstraintKinds #-}
{-# language FlexibleInstances #-}
{-# language TypeOperators #-}
{-# language ScopedTypeVariables #-}
{-# language DefaultSignatures #-}
{-# language FunctionalDependencies #-}
{-# language UndecidableSuperClasses #-}
{-# language UndecidableInstances #-}
{-# language TypeInType #-}
import GHC.Types (Constraint, Type)
import qualified Prelude
type Cat i = i -> i -> Type
newtype Y (p :: i -> j -> Type) (a :: j) (b :: i) = Y { getY :: p b a }
class Vacuous (a :: i)
instance Vacuous a
class (Functor p, Dom p ~ Op p, Cod p ~ Nat p (->)) => Category (p :: Cat
i) where
type Op p :: Cat i
type Op p = Y p
type Ob p :: i -> Constraint
type Ob p = Vacuous
class (Category (Dom f), Category (Cod f)) => Functor (f :: i -> j) where
type Dom f :: Cat i
type Cod f :: Cat j
class (Functor f, Dom f ~ p, Cod f ~ q) => Fun (p :: Cat i) (q :: Cat
j) (f :: i -> j) | f -> p q
instance (Functor f, Dom f ~ p, Cod f ~ q) => Fun (p :: Cat i) (q :: Cat
j) (f :: i -> j)
data Nat (p :: Cat i) (q :: Cat j) (f :: i -> j) (g :: i -> j)
instance (Category p, Category q) => Category (Nat p q) where
type Ob (Nat p q) = Fun p q
instance (Category p, Category q) => Functor (Nat p q) where
type Dom (Nat p q) = Y (Nat p q)
type Cod (Nat p q) = Nat (Nat p q) (->)
instance (Category p, Category q) => Functor (Nat p q f) where
type Dom (Nat p q f) = Nat p q
type Cod (Nat p q f) = (->)
instance Category (->)
instance Functor ((->) e) where
type Dom ((->) e) = (->)
type Cod ((->) e) = (->)
instance Functor (->) where
type Dom (->) = Y (->)
type Cod (->) = Nat (->) (->)
instance (Category p, Op p ~ Y p) => Category (Y p) where
type Op (Y p) = p
instance (Category p, Op p ~ Y p) => Functor (Y p a) where
type Dom (Y p a) = Y p
type Cod (Y p a) = (->)
instance (Category p, Op p ~ Y p) => Functor (Y p) where
type Dom (Y p) = p
type Cod (Y p) = Nat (Y p) (->)
}}}
Here I need the circular definition of `Fun` to talk about the fact that
the objects in the category of natural transformations from a category p
to a category q are functors with domain p and codomain q, so to give the
definition of the class-associated `type Ob (Nat p q)` I need such a
cyclic definition.
I can't leave the domain and codomain of `Functor` in fundeps, otherwise
if I go to define a subclass of Functor I'd have to include the arguments,
and I have a ''lot'' of those subclasses!
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11523>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list