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?

È stato utile?

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)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top