2010-10-19 6 views
15

Ce code fonctionne:entier flotter

posToXY :: Float -> Float -> Integer 
posToXY a b = do 
     let y = a/b 
     round y 

Mais cela ne fonctionne pas:

posToXY :: Integer -> Integer -> Integer 
posToXY a b = do 
     let y = a/b 
     round y 

Je comprends que l'opération '/' ne définit pas pour le type entier, mais je n » Je sais comment corriger le code pour qu'il fonctionne avec les paramètres Integer.

+0

Voir aussi http://stackoverflow.com/questions/1397210/haskell-converting-float-to-int –

+0

Et aussi http: //stackoverflow.com/questions/3275193/whats-the-right-way-to-divide-two-int-values-to-obtain-a-float –

Répondre

22

Si vous souhaitez effectuer division fractionnaire, vous pouvez convertir tout type Integral utilisant fromIntegral, ou fromInteger pour convertir uniquement à partir de Integer spécifiquement.

Il y a des fonctions similaires relatives à d'autres classes de type numérique: toRational, fromRational, realToFrac, etc. Et bien sûr, vous pouvez convertir les types fractionnaires retour à des types entiers en utilisant round, floor, ceiling ou tel.

Et enfin, hasard que vous vouliez réellement entier division, au lieu de division fractionnaire avec arrondi après, il y a les div et quot fonctions (en fonction de ce que le comportement troncature que vous voulez).

De même, vous devriez écrire votre fonction comme posToXY a b = round $ a/b. Les lignes inutiles do rendent la lecture plus difficile.

+0

'posToXY ab = rond $ a/b' - dans ce Pour ma part, je préfère les parenthèses pour la lisibilité - cela évite d'avoir à réfléchir (même pour une fraction de seconde) sur la priorité de l'opérateur, et cela ressemble plus à l'expression mathématique qu'il représente. – mokus

+0

@mokus: Oui, je suis d'accord. J'ai seulement utilisé '($)' par habitude, j'aurais probablement utilisé des parenthèses dans le code réel. –

+0

@ C.A.McCann * 'vous devriez probablement écrire votre fonction comme ...' * - suggérez-vous de mieux fusionner les deux fonctions en une seule? – Wolf

7

Vous pouvez utiliser fromIntegral pour convertir n'importe quel type Integral en n'importe quel type Num. Alors:

let y = fromIntegral a/fromIntegral b 
7

Votre code pourrait facilement être simplifié pour

posToXY :: Float -> Float -> Integer 
posToXY a b = round (a/b) 

Puis

posToXY :: Integer -> Integer -> Integer 
posToXY a b = round (fromIntegral a/fromIntegral b) 
3

Si vous voulez une division entière, vous pouvez utiliser div.

posToXY :: Integer -> Integer -> Integer 
posToXY = div 

Notez que cela ne fait la même chose que l'arrondi d'une division à virgule flottante, car div arrondit toujours vers le bas.

Pour une signature de type plus général, vous pouvez le faire à la place

p :: (Real a, Real a1, Integral b) => a -> a1 -> b 
posToXY a b = round (realToFrac a/realToFrac b) 
Questions connexes