Condición de cobertura liberal introducida en GHC 7.7 rompe el código válido en GHC 7.6

La idea

Estoy escribiendo unDSL, que compila a haskell.

Los usuarios de este lenguaje pueden definir sus propias estructuras de datos inmutables y funciones asociadas. Por función asociada me refiero a una función, que pertenece a una estructura de datos. Por ejemplo, el usuario puede escribir (en pseudocódigo "pythonic"):

data Vector a:
  x,y,z :: a
  def method1(self, x):
      return x

(que es equivalente al siguiente código, pero también muestra que las funciones asociadas se comportan como clases de tipo con suposición de mundo abierto):

data Vector a:
  x,y,z :: a
def Vector.method1(self, x):
  return x

En este ejemplo,method1 es una función asociada conVector tipo de datos, y puede ser utilizado comov.testid(5) (dóndev es instancia deVector tipo de datos).

Estoy traduciendo dicho código al código de Haskell, pero estoy enfrentando un problema que estoy tratando de resolver durante mucho tiempo.

El problema

Estoy tratando de mover el código de GHC 7.6 sobreGHC 7.7 (que es pre-lanzamiento de 7.8) (Se pueden compilar nuevas versionesde fuentes). El código funciona perfectamente bajo GHC 7.6, pero no lo hace bajo GHC 7.7. Quiero preguntarle cómo puedo solucionarlo para que funcione en la nueva versión del compilador.

Código de ejemplo

Veamos una versión simplificada del código Haskell generado (por mi compilador):

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FunctionalDependencies #-}

import Data.Tuple.OneTuple

------------------------------
-- data types
------------------------------
data Vector a = Vector {x :: a, y :: a, z :: a} deriving (Show)
-- the Vector_testid is used as wrapper over a function "testid". 
newtype Vector_testid a = Vector_testid a

------------------------------
-- sample function, which is associated to data type Vector
------------------------------
testid (v :: Vector a) x = x

------------------------------
-- problematic function (described later)
------------------------------
testx x = call (method1 x) $ OneTuple "test"

------------------------------
-- type classes
------------------------------
-- type class used to access "method1" associated function
class Method1 cls m func | cls -> m, cls -> func where 
    method1 :: cls -> m func

-- simplified version of type class used to "evaluate" functions based on 
-- their input. For example: passing empty tuple as first argument of `call` 
-- indicates evaluating function with default arguments (in this example 
-- the mechanism of getting default arguments is not available)
class Call a b where
    call :: a -> b

------------------------------
-- type classes instances
------------------------------
instance (out ~ (t1->t1)) => Method1 (Vector a) Vector_testid out where
  method1 = (Vector_testid . testid)

instance (base ~ (OneTuple t1 -> t2)) => Call (Vector_testid base) (OneTuple t1 -> t2) where
    call (Vector_testid val) = val

------------------------------
-- example usage
------------------------------
main = do
    let v = Vector (1::Int) (2::Int) (3::Int)
    -- following lines equals to a pseudocode of ` v.method1 "test" `
    -- OneTuple is used to indicate, that we are passing single element.
    -- In case of more or less elements, ordinary tuples would be used.
    print $ call (method1 v) $ OneTuple "test"
    print $ testx v

El código compila y funciona bien con GHC 7.6. Cuando intento compilarlo con GHC 7.7, obtengo el siguiente error:

debug.hs:61:10:
    Illegal instance declaration for
      ‛Method1 (Vector a) Vector_testid out’
      The liberal coverage condition fails in class ‛Method1’
        for functional dependency: ‛cls -> func’
      Reason: lhs type ‛Vector a’ does not determine rhs type ‛out’
    In the instance declaration for
      ‛Method1 (Vector a) Vector_testid out’

El error se debe a las nuevas reglas de verificación de lo que pueden hacer las dependencias funcionales, a saber:liberal coverage condition (Hasta donde sé, esto escoverage condition relajado usando-XUndecidableInstances)

Algunos intentan solucionar el problema

Estaba tratando de superar este problema cambiando la definición deMethod1 a:

class Method1 cls m func | cls -> m where 
    method1 :: cls -> m func

Lo que resuelve el problema con las dependencias funcionales, pero luego la línea:

testx x = call (method1 x) $ OneTuple "test"

Ya no está permitido, lo que provoca un error de compilación (en las versiones 7.6 y 7.7):

Could not deduce (Method1 cls m func0)
  arising from the ambiguity check for ‛testx’
from the context (Method1 cls m func,
                  Call (m func) (OneTuple [Char] -> s))
  bound by the inferred type for ‛testx’:
             (Method1 cls m func, Call (m func) (OneTuple [Char] -> s)) =>
             cls -> s
  at debug.hs:50:1-44
The type variable ‛func0’ is ambiguous
When checking that ‛testx’
  has the inferred type ‛forall cls (m :: * -> *) func s.
                         (Method1 cls m func, Call (m func) (OneTuple [Char] -> s)) =>
                         cls -> s’
Probable cause: the inferred type is ambiguous

EDITAR:

También es imposible resolver este problema utilizando familias de tipos (que yo sepa). Si reemplazamosMethod1 tipo de clase e instancias con el siguiente código (o similar):

class Method1 cls m | cls -> m where 
    type Func cls
    method1 :: cls -> m (Func cls)

instance Method1 (Vector a) Vector_testid where
    type Func (Vector a) = (t1->t1)
    method1 = (Vector_testid . testid)

Tendríamos error obvioNot in scope: type variable ‛t1’, porque las familias de tipos no permiten usar tipos, lo que no aparece en LHS de la expresión de tipo.

La pregunta final

¿Cómo puedo hacer que esta idea funcione bajo GHC 7.7? Se lo nuevoliberal coverage condition permite a los desarrolladores de GHC hacer algún progreso con la comprobación de tipos, pero de alguna manera debería ser posible para la idea de puerto que funciona en GHC 7.6 sobre la versión de compilador nunca.

(Sin forzar al usuario de mi DSL a introducir más tipos, todo hasta ahora, como las instancias de clase de tipo, estoy usando la plantilla Haskell)

Respuestas a la pregunta(1)

Su respuesta a la pregunta