Ne pouvais pas faire correspondre le type `Int' avec un réel de type `Integer'
J'ai le texte suivant du code Haskell:
-- Problem 69
import ProjectEuler
phi :: Integer -> Integer
phi n = n * product [p - 1 | p <- primeDivisors n] `div` product [p | p <- primeDivisors n]
-- primeDivisors n is a list of the prime divisors of n
maxRatio :: (Int, Int, Double) -> (Int, Int, Double) -> (Int, Int, Double)
maxRatio t1@(_, _, x) t2@(_, _, y)
| x > y = t1
| otherwise = t2
main = print (foldl
maxRatio
(0, 0, 0.0)
[(n, phi n, ratio) | n <- [2..max], let ratio = fromIntegral n / (fromIntegral (phi n))]
)
where max = 1000
qui donne l'erreur suivante:
Couldn't match expected type `Int' with actual type `Integer'
In the expression: n
In the expression: (n, phi n, ratio)
In the third argument of `foldl', namely
`[(n, phi n, ratio) |
n <- [2 .. max],
let ratio = fromIntegral n / (fromIntegral (phi n))]'
Je soupçonne que, dans le triple (0, 0, 0.0)
les 0 sont de type Int
. Est 0
toujours de type Int
ou est ghci en déduire le type de Int
dans ce cas? Si plus tard, comment puis-je le forcer à être de type Integer
à la place? Ou est-il autre chose que la cause de cette erreur?
OriginalL'auteur Code-Apprentice | 2012-09-05
Vous devez vous connecter pour publier un commentaire.
Haskell peut généralement déduire le type de littéraux numériques tels que les
0
que n'importe quel type approprié vous avez besoin. C'est parce qu'il sait quelles sont les fonctions que vous les transmettre; si j'ai une fonctionphi :: Integer -> Integer
, et j'appellephi 0
, Haskell sait que c'0
doit avoir été unInteger
. C'est aussi bien si je appeler une fonctionpho :: Int -> Int
avecpho 0
; que particulier0
est déduit d'uneInt
.Cependant
Int
etInteger
sont de types différents, et il n'y a pas qu'une seule façon particulière0
peut être transmis à la foisphi
etpho
.Votre problème est tout simplement que les tuples qui
maxRatio
traite sont typés (par vous)(Int, Int, Double)
, mais qu'un tel n-uplet est construit comme(n, phi n, ratio)
. Depuisphi
prend et retourneInteger
, len
dans l'expression doit être uneInteger
. Mais cela ne fonctionne pas pourmaxRatio
, de sorte que vous obtenez le message d'erreur.Selon le type que vous en fait voulu (
Int
ouInteger
), tout ce que vous devez faire est de changer le type de signature dephi
oumaxRatio
afin qu'ils travaillent avec le même genre de numéro. Haskell décider que votre écrit littéralement0
s est ce type numérique est nécessaire pour faire ce travail, fourni il en est un qui peut le faire fonctionner!Notez que le message d'erreur messaged spécifiquement vous a dit qu'il était
n
dans(n, phi n, ratio)
qui devait être unInt
et était en fait unInteger
. Le(0, 0, 0.0)
tuple n'est jamais mentionné. Souvent des erreurs de type proviennent ailleurs que là où le compilateur points (vu que tout le compilateur peut faire est de repérer que les différentes chaînes de l'inférence de produire incompatible exigences sur le type de quelque chose, avec aucun moyen de savoir quelle partie de l'ensemble du processus est "mal"), mais dans ce cas, il fait très bien.Haskell obtient une (assez justifié) mauvaise réputation de mystérieux messages d'erreur, mais il peut aider beaucoup à partir de ce que le compilateur vous dit, c'est le problème et essayer de comprendre pourquoi des faits, il se plaint de survenir à partir de votre code. Ce sera douloureux au début, mais vous aurez à développer rapidement une alphabétisation de base dans Haskell messages d'erreur (au moins les plus simples) qui va vous aider à repérer ces types d'erreurs très rapidement, ce qui rend le compilateur d'une très puissant de détection des erreurs système pour vous.
0
était polymorphe dans son genre, mais mon noob yeux ne pouvaient pas voir une autre raison pour l'inférence de type qui a donné à l'erreur. Bien sûr, j'ai tout simplement raté mon explicite de la déclaration de type pourmaxRatio
.OriginalL'auteur Ben
n
est déduit queInt
en raison du type demaxRatio
, bien que le type dephi
dit qu'il devrait êtreInteger
. La solution la plus simple est de changer le type demaxRatio
à utiliserInteger
ou même justea
puisqu'il ne touche pas à ces valeurs.OriginalL'auteur hammar
C'est soit déduit, de sorte que vous pouvez simplement modifier le type de signature de
maxRatio
. Encore, si jamais vous avez besoin de changer une expliciteInt
à unInteger
, utiliseztoInteger :: (Integral a) => a -> Integer
fromIntegeral
, surtout quand je suis en utilisantlength
. Est-il une différence entre l'utilisation defromIntegral
plutôt quetoInteger
?Je pense que la seule différence est que
fromIntegral
pouvez retourner n'importe quelNum
type, donc c'est un peu moins clair lors de la lecture de ce type, il va être déduit que.en fait,
fromIntegral
est défini commefromIntegral = fromInteger . toInteger
-- donc, c'est certainement juste un compromis entre la flexibilité et la lisibilitéOriginalL'auteur amindfv
Votre type de signatures sont incompatibles - remplacer
Int
avecInteger
tout au long de.OriginalL'auteur AndrewC