2009-04-03 18 views
6

Cabbage.hs:Perché questo tipo di variabile è ambigua?

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

Quando compilo (con GHC) ottengo questo messaggio di errore:

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) 

Non capisco il motivo per cui a è ambigua. Sicuramente il a nella riga 7 è lo stesso del a nella riga 6? Come posso risolvere questo?

In alternativa, c'è un modo migliore per dichiarare una costante per istanza?

risposta

11

Utilizzando le variabili di tipo scoped è possibile far sapere a GHC che lo undefined :: a dovrebbe essere lo stesso (altrimenti a è solo una scorciatoia per forall a. a). variabili di tipo con ambito devono quindi essere esplicitamente forall-qualificata:

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

Il problema è che Haskell non sa quale istanza di Cabbage corrisponde a foo. Per quanto ne so, non corrisponde al a in (undefined :: a) con l'a in quux :: Cabbage a => String -> a

Partendo dal presupposto che è quello che vuoi, si può fare questo:

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

Questa lega foo e bar insieme in modo che usa la stessa istanza per entrambi, e dal momento che in realtà non è necessario il valore dell'input per foo, si spegne. Non conosco un modo migliore di fare costanti per istanza però. Speriamo che arrivi qualcun altro che lo fa.

2

si può estrarre la parte polimorfico in funzione

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