Haskell: résultat de conversion problème de la division de type intégral
Question
J'apprends Haskell et coincé à essayer de comprendre le système de type.
Je suis en train d'écrire une fonction qui renvoie la longueur de la série demi-pension ou trois plus un »pour une entrée. Voici ma tentative de la fonction, en utilisant une approche récursive (la fonction est valable pour les entrées intégrales uniquement):
hotpo :: (Integral a) => a->a
hotpo n = hotpoHelper n 1
hotpoHelper:: (Integral a) => a->a->a
hotpoHelper 1 n = n
hotpoHelper num count
| even num = hotpoHelper (truncate (num/2)) (count+1)
| otherwise = hotpoHelper (3*num+1) (count+1)
Voici l'erreur que je reçois lorsque je tente de charger ce fichier dans GHC 6.12.3
test.hs:8:30:
Could not deduce (RealFrac a) from the context (Integral a)
arising from a use of `truncate' at test.hs:8:30-45
Possible fix:
add (RealFrac a) to the context of
the type signature for `hotpoHelper'
In the first argument of `hotpoHelper', namely
`(truncate (num / 2))'
In the expression: hotpoHelper (truncate (num / 2)) (count + 1)
In the definition of `hotpoHelper':
hotpoHelper num count
| even num = hotpoHelper (truncate (num / 2)) (count + 1)
| otherwise = hotpoHelper (3 * num + 1) (count + 1)
take (truncate (5/2)) [1,2,3]
fonctionne, donc je suis incapable de comprendre ce message d'erreur.
Où vais-je tort?
La solution
L'opérateur /
dans Haskell est utilisé pour la division à virgule flottante. Si vous ne voulais vraiment utiliser la division à virgule flottante et truncate
, vous utiliseriez fromIntegral
sur num
premier à le convertir en un nombre à virgule flottante. L'erreur que vous obtenez dit que vous ne pouvez pas utiliser division fractionnaire sur un nombre entier (5/2 fonctionne parce que le compilateur infère un type à virgule flottante pour les deux numéros). Cependant, vous pouvez faire ce que vous voulez beaucoup plus facilement, en utilisant la fonction div
. Ceci est généralement utilisé infix, en entourant le nom de la fonction avec backquotes (cela fonctionne pour toute fonction Haskell):
| even num = hotpoHelper (num `div` 2) (count+1)