Ambigu variable de type " a0 " dans les contraintes
Je suis en train de passer à travers le YesNo
exemple de Learn You a Haskell for Great Good!
livre.
Voici mon code source:
module Main where
main :: IO ()
main = putStrLn ( show (yesno 12) )
class YesNo a where
yesno :: a -> Bool
instance YesNo Bool where
yesno b = b
instance YesNo [a] where
yesno [] = False
yesno _ = True
instance YesNo Int where
yesno 0 = False
yesno _ = True
Lorsque j'exécute ce code à la suite de l'exception se produit:
Ambiguous type variable `a0' in the constraints:
(YesNo a0) arising from a use of `yesno'
at /Users/mkhadikov/Projects/personal/haskell/hello-world/yesno.hs:5:25-29
(Num a0) arising from the literal `12'
at /Users/mkhadikov/Projects/personal/haskell/hello-world/yesno.hs:5:31-32
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `show', namely `(yesno 12)'
In the first argument of `putStrLn', namely `(show (yesno 12))'
In the expression: putStrLn (show (yesno 12))
Pouvez-vous nous expliquer quel est le problème avec ce code?
Vous devez vous connecter pour publier un commentaire.
Le problème est qu'il ne sait pas de quel type 12 est! Il peut être tout type avec un Num exemple:
Vous devez spécifier le type que vous souhaitez directement: essayez
putStrLn (show (yesno (12 :: Int)))
.Pourquoi ne peut-GHC pick de type Int, car aucun autre choix serait de travailler, vous demandez-vous? Bonne question. La réponse est que, avec Haskell typeclass système, l'ajout d'une instance ne peut jamais invalider existant correcte de programmes ou de modifier leur comportement. (Ce qui est dénommé le monde ouvert hypothèse.) Si c'était le pick de type Int, alors qu'arriverait-il si vous avez ajouté
instance YesNo Integer
? Le choix serait devenue ambiguë, et votre programme de casser!Ainsi, lorsque vous voulez utiliser un typeclass comme ça avec un polymorphe de la valeur, vous devez spécifier quel type de vous dire avec plus de précision. Cela ne devrait pas beaucoup dans la pratique, puisqu'il y a généralement être certains contexte de forcer le type à être ce que vous voulez; c'est principalement les littéraux numériques qui sont touchés par cette.
Le problème est que
12
a effectivement un typeNum a => a
et pasInt
que vous attendez. Si vous ajoutez un type explicite anotation comme12 :: Int
, il doit compiler.12
en haskell? Il semble que chaque fois que vous créer une base de données constructeur, il construit une valeur d'un type unique. Mais quand vous écrivez12
, comme vous pouvez le voir il construit n'est pas une valeur d'un type unique, mais tout type de valeur dont le type est limitée par Num. AinsiNum a => a
. Suis-je interpréter cela correctement? C'est cette sorte de comme la construction d'une valeur qui a une existentiel/union?Num
contient une fonctionfromInteger :: Num a => Integer -> a
. Un littéral numérique fonctionne comme sifromInteger
a été appelée sur elle.a
ne sorte de devenir existentiel/de l'union. Très intéressante.forall
; le type pleinement qualifié estfromInteger :: forall a. Num a => Integer -> a
. DepuisfromInteger
est une classe de type de membre, ghci choisit la mise en œuvre defromInteger
approprié pour le type que vous souhaitez obtenir.exists a.
rendrait existentielle.fromSomething
pour votre propre type de classe?Integer
et vous devez la convertir en une variable de type. Il semble que vous en avez confuse sur la terminologie ici. Je pense que tu veux dire votre propre type et pas votre propre type de classe.fromInteger
fonction? Non seulement le type de signature.Num
a sa propre mise en œuvre defromInteger
. Vous voudrez peut-être lire à propos de les classes de type pour comprendre ce qui se passe ici.J'ai eu le même problème.
C'est une solution, peut-être pas la meilleure, mais elle fonctionne: