2009-04-03 15 views
6

Cabbage.hs:Warum ist diese Art Variable mehrdeutig?

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)) 

Als ich (mit ghc) kompilieren bekomme ich diese Fehlermeldung:

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) 

Ich verstehe nicht, warum a nicht eindeutig ist. Sicher ist die a in Zeile 7 die gleiche wie die a in Zeile 6? Wie behebe ich das?

Oder gibt es eine bessere Möglichkeit, eine pro-Instanz konstant zu deklarieren?

Antwort

11

Mit Variablen vom Geltungsbereich können Sie GHC wissen lassen, dass die undefined :: a die gleiche sein sollte (ansonsten ist a nur eine Kurzschrift für forall a. a). Scoped Typ Variablen muß dann explizit forall-qualifiziert sein:

{-# 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

Das Problem ist, dass Haskell nicht weiß, welche Instanz von Cabbage, die foo entspricht dort ist. So weit ich weiß, ist es nicht die a in (undefined :: a) übereinstimmen mit der a in quux :: Cabbage a => String -> a

Unter der Annahme, dass das, was Sie wollen, können Sie dies tun:

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

Diese foo bindet und eine Bar zusammen, so dass es verwendet die gleiche Instanz für beide, und da Sie den Wert der Eingabe für foo nicht wirklich benötigen, wird es knapp. Ich kenne jedoch keinen besseren Weg, um Konstanten pro Instanz zu machen. Hoffentlich kommt jemand anderes, der das tut.

2

Sie den polymorphen Teil als Funktion extrahieren können

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