2009-04-03 12 views
6

Cabbage.hs:¿Por qué este tipo de variable es ambiguo?

module Cabbage where 
class Cabbage a 
    where foo :: a -> String  -- the parameter is only present for its type, 
           -- the parameter value will be ignored 
     bar :: String -> a 
quux :: Cabbage a => String -> a 
quux s = bar (s ++ foo (undefined :: a)) 

Cuando compilo (con GHC) me sale este mensaje de error:

Cabbage.hs:7:19: 
    Ambiguous type variable `a' in the constraint: 
     `Cabbage a' arising from a use of `foo' at Cabbage.hs:7:19-38 
    Probable fix: add a type signature that fixes these type variable(s) 

No entiendo por qué a es ambigua. Sin duda, el a en la línea 7 es el mismo que el a en la línea 6? ¿Cómo puedo solucionar esto?

Alternativamente, ¿existe una forma mejor de declarar una constante por instancia?

Respuesta

11

Utilizando variables de tipo de ámbito, puede dejar que GHC sepa que el undefined :: a debe ser el mismo (de lo contrario, a es solo una abreviatura de forall a. a). Las variables de tipo de ámbito deben entonces ser explícitamente forall cualificado:

{-# LANGUAGE ScopedTypeVariables #-} 
module Cabbage where 
class Cabbage a 
    where foo :: a -> String  -- the parameter is only present for its type, 
           -- the parameter value will be ignored 
     bar :: String -> a 
quux :: forall a. Cabbage a => String -> a 
quux s = bar (s ++ foo (undefined :: a)) 
2

El problema es que Haskell no sabe qué instancia de Cabbage que foo corresponde a allí. Por lo que yo sé, que no coincide con el a en (undefined :: a) con el a en quux :: Cabbage a => String -> a

Suponiendo que es lo que desea, usted puede hacer esto:

quux :: Cabbage a => String -> a 
quux s = result 
    where result = bar (s ++ foo result) 

Esto se relaciona foo y bar juntos para que usa la misma instancia para ambos, y como en realidad no necesitas el valor de la entrada para foo, toca fondo. Sin embargo, no sé de una forma mejor de hacer constantes por instancia. Con suerte, alguien más vendrá y lo hará.

2

uno puede extraer la parte polimórfica en función

quux :: Cabbage a => String -> a 
quux s = quux' undefined 
    where quux' :: Cabbage a => a -> a 
      quux' x = bar (s ++ foo x) 
Cuestiones relacionadas