#7100: Loosen requirement for free variables in constraint in class declaration
---------------------------------+------------------------------------------
    Reporter:  selinger          |       Owner:                  
        Type:  feature request   |      Status:  new             
    Priority:  normal            |   Milestone:                  
   Component:  Compiler          |     Version:  7.4.2           
    Keywords:                    |          Os:  Unknown/Multiple
Architecture:  Unknown/Multiple  |     Failure:  None/Unknown    
  Difficulty:  Unknown           |    Testcase:                  
   Blockedby:                    |    Blocking:                  
     Related:                    |  
---------------------------------+------------------------------------------
Changes (by simonpj):

  * difficulty:  => Unknown


Old description:

> In a class declaration, Haskell requires all free variables that occur in
> the constraint to also occur as class parameters. Thus, the following is
> not allowed:
>
> class MyClass a b | a -> b
> instance MyClass Int Bool
> instance MyClass a b => MyClass [a] [b]
>
> class MyClass a b => ConvenienceClass a
>
> Note, however, that due to functional dependencies, b is completely
> determined by a. There is indeed a workaround that allows the above
> ConvenienceClass to be defined. This requires defining a type family to
> witness each functional constraint:
>
> type family MyClass_FD_Witness a
> class (MyClass_FD_Witness a ~ b) => MyClass a b | a -> b
>
> type instance MyClass_FD_Witness Int = Bool
> instance MyClass Int Bool
>
> type instance MyClass_FD_Witness [a] = [MyClass_FD_Witness a]
> instance MyClass a b => MyClass [a] [b]
>
> class MyClass a (MyClass_FD_Witness a) => Convenience a
>
> Clearly, whenever there is a functional dependency, it is possible, in
> the above way, to define a type family witnessing it. However, the
> resulting definitions are very long and cumbersome, particularly if
> functional dependencies are composed, or if a dependent variable is used
> many times in a constraint.
>
> To illustrate this in a real-life example, here is a line of code that I
> have written in an actual application:
>
> class (MonadCurry fun (MonadArgType fun) m a, Curry (CurryType
> (MonadArgType fun) String) (MonadArgType fun) String, PrintfType
> (CurryType (MonadArgType fun) String)) => WPrintf fun m a
>
> What I really meant to write was:
>
> class (MonadCurry fun arg m a, Curry fun' arg String, PrintfType fun') =>
> WPrintf fun m a
>
> The relevant functional dependencies are:
>
> class MonadCurry fun args m res | args m res -> fun, fun -> m args res
> class Curry fun args res | args res -> fun
>
> It would be desirable (and, I believe, sound for the above reason) to
> have a language option that relaxes the requirement on type variables
> occurring in constraints of class declaration, so that each such type
> variable must only be reachable from parameters of the class via
> functional dependencies.

New description:

 In a class declaration, Haskell requires all free variables that occur in
 the constraint to also occur as class parameters. Thus, the following is
 not allowed:
 {{{
 class MyClass a b | a -> b
 instance MyClass Int Bool
 instance MyClass a b => MyClass [a] [b]

 class MyClass a b => ConvenienceClass a
 }}}
 Note, however, that due to functional dependencies, b is completely
 determined by a. There is indeed a workaround that allows the above
 `ConvenienceClass` to be defined. This requires defining a type family to
 witness each functional constraint:
 {{{
 type family MyClass_FD_Witness a
 class (MyClass_FD_Witness a ~ b) => MyClass a b | a -> b

 type instance MyClass_FD_Witness Int = Bool
 instance MyClass Int Bool

 type instance MyClass_FD_Witness [a] = [MyClass_FD_Witness a]
 instance MyClass a b => MyClass [a] [b]

 class MyClass a (MyClass_FD_Witness a) => Convenience a
 }}}
 Clearly, whenever there is a functional dependency, it is possible, in the
 above way, to define a type family witnessing it. However, the resulting
 definitions are very long and cumbersome, particularly if functional
 dependencies are composed, or if a dependent variable is used many times
 in a constraint.

 To illustrate this in a real-life example, here is a line of code that I
 have written in an actual application:
 {{{
 class (MonadCurry fun (MonadArgType fun) m a,
        Curry (CurryType (MonadArgType fun) String) (MonadArgType fun)
 String,
        PrintfType (CurryType (MonadArgType fun) String))
     => WPrintf fun m a
 }}}
 What I really meant to write was:
 {{{
 class (MonadCurry fun arg m a,
        Curry fun' arg String,
        PrintfType fun')
     => WPrintf fun m a
 }}}
 The relevant functional dependencies are:
 {{{
 class MonadCurry fun args m res
     | args m res -> fun, fun -> m args res

 class Curry fun args res | args res -> fun
 }}}
 It would be desirable (and, I believe, sound for the above reason) to have
 a language option that relaxes the requirement on type variables occurring
 in constraints of class declaration, so that each such type variable must
 only be reachable from parameters of the class via functional
 dependencies.

--

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/7100#comment:2>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler

_______________________________________________
Glasgow-haskell-bugs mailing list
Glasgow-haskell-bugs@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to