Perché questo tipo di variabile ambigua?
-
23-08-2019 - |
Domanda
Cabbage.hs:
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
in linea 7 è la stessa della a
nella linea 6? Come posso risolvere questo problema?
In alternativa, c'è un modo migliore di dichiarazione di una costante per-esempio?
Soluzione
Utilizzando le variabili di tipo con ambito si può lasciare GHC sapere che il 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-qualificati:
{-# 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))
Altri suggerimenti
Il problema è che Haskell non sa quale esempio di Cabbage
che foo
corrisponde a lì. 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 utilizzi la stessa istanza per entrambi, e dal momento che in realtà non è necessario il valore dell'ingresso per foo, in fondo. Io non conosco un modo migliore di fare le costanti per-caso però. Speriamo che qualcun altro verrà lungo che lo fa.
è possibile 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)