Surutilisation de fromIntegral à Haskell
chaque fois que j'écris une fonction en utilisant des doubles et des entiers, je trouve ce problème où je dois constamment utiliser "frommintegral" partout dans ma fonction. Par exemple:
import Data.List
roundDouble
:: Double
-> Int
-> Double
roundDouble x acc = fromIntegral (round $ x * 10 ** fromIntegral acc) / 10 ** fromIntegral acc
y a-t-il une façon plus facile d'écrire ceci? (Je sais il peut y avoir des moyens plus faciles de l'arrondi d'un nombre et s'il vous plaît laissez-moi savoir! Cependant, je m'intéresse principalement à la façon d'éviter d'utiliser autant de "frommintegrals".)
Merci, Ash
4 réponses
Parfois je trouve utile une fonction d'aide:
roundDouble x acc = (round $ x * 10 ^ acc) /. (10 ^ acc)
where
x /. y = fromIntegral x / fromIntegral y
que la fonction helper peut également être écrit:
(/.) = (/) `on` fromIntegral
où on
est de Data.Function
.
vous pouvez utiliser ^
au lieu de **
. ^
prend n'importe quelle intégrale comme deuxième argument, donc vous n'avez pas besoin d'appeler fromIntegral
sur le deuxième opérande. Ainsi votre code devient:
roundDouble X acc = frommintegral (round $ x * 10 ^ acc) / 10 ^ acc
Qui n'a qu'un seul fromIntegral
. Et celui que vous ne pouvez pas vous débarrasser comme round
renvoie naturellement une intégrale et vous ne pouvez pas effectuer la division non-entière sur un Intégrante.
j'ai un problème similaire avec le code de composition, où fromIntegral
est utilisé pour convertir CInt en Int. Je définis habituellement fI = fromIntegral
pour le rendre plus facile. Vous pouvez également avoir besoin de lui donner une signature de type explicite ou utiliser-XNoMonomorphismRestriction.
si vous faites beaucoup de mathématiques, vous pourriez vouloir regarder le Prélude numérique , qui semble avoir des relations beaucoup plus sensées entre les différents types numériques.
une autre idée, similaire à luqui . La plupart de mes problèmes avec fromIntegral
sont liés à la nécessité de diviser Int
par Double
ou Double
par Int
. Ainsi ce (/.)
permet de diviser deux Real
types, pas nécessairement les mêmes, pas nécessairement Integral
types comme dans la solution de luqui:
(/.) :: (Real a, Real b, Fractional c) => a -> b -> c
(/.) x y = fromRational $ (toRational x) / (toRational y)
exemple:
ghci> let (a,b,c) = (2::Int, 3::Double, 5::Int)
ghci> (b/.a, c/.a, a/.c)
(1.5,2.5,0.4)
il fonctionne pour deux Real
s, mais je soupçonne que la division rationnelle et la conversion en/de Rational
ne sont pas très efficaces.
maintenant votre exemple devient:
roundDouble :: Double -> Int -> Double
roundDouble x acc = (round $ x * 10 ^ acc) /. (10 ^ acc)