float - frominteger haskell
Uso excesivo de fromIntegral en Haskell (4)
A veces encuentro útil una función de ayuda:
roundDouble x acc = (round $ x * 10 ^ acc) /. (10 ^ acc)
where
x /. y = fromIntegral x / fromIntegral y
Esa función auxiliar también se puede escribir:
(/.) = (/) `on` fromIntegral
Donde on
es de Data.Function
.
Cada vez que escribo una función usando dobles y enteros, encuentro este problema donde constantemente tengo que usar ''fromIntegral'' en todas partes en mi función. Por ejemplo:
import Data.List
roundDouble
:: Double
-> Int
-> Double
roundDouble x acc = fromIntegral (round $ x * 10 ** fromIntegral acc) / 10 ** fromIntegral acc
¿Hay una forma más fácil de escribir esto? (Sé que puede haber formas más fáciles de redondear un número y, si las hay, hágamelo saber. Sin embargo, me interesa sobre todo cómo evitar el uso de tantos "desde los Integrales").
Gracias ash
Otra idea, similar a la de luqui''s . La mayoría de mis problemas con fromIntegral
están relacionados con la necesidad de dividir Int
por Double
o Double
por Int
. Entonces (/.)
Permite dividir cualquiera de los dos tipos Real
, no necesariamente iguales, y no necesariamente tipos Integral
como en la solución de luqui:
(/.) :: (Real a, Real b, Fractional c) => a -> b -> c
(/.) x y = fromRational $ (toRational x) / (toRational y)
Ejemplo:
ghci> let (a,b,c) = (2::Int, 3::Double, 5::Int)
ghci> (b/.a, c/.a, a/.c)
(1.5,2.5,0.4)
Funciona para dos Real
, pero sospecho que la división racional y la conversión a / desde Rational
no son muy efectivas.
Ahora tu ejemplo se convierte en:
roundDouble :: Double -> Int -> Double
roundDouble x acc = (round $ x * 10 ^ acc) /. (10 ^ acc)
Puedes usar ^
lugar de **
. ^
toma cualquier Integral como segundo argumento, por lo que no es necesario que llames desde fromIntegral
al segundo operando. Entonces tu código se convierte en:
roundDouble x acc = fromIntegral (round $ x * 10 ^ acc) / 10 ^ acc
Que solo tiene uno de fromIntegral
. Y ese que no puede deshacerse ya que la round
naturalmente devuelve un Integral y no puede realizar una división no entera en un Integral.
Tengo un problema similar con el código de fromIntegral
, donde se utiliza fromIntegral
para convertir CInt a Int. Generalmente defino fI = fromIntegral
para hacerlo más fácil. Es posible que también deba darle una firma de tipo explícita o usar -XNoMonomorphismRestriction.
Si estás haciendo muchos cálculos, es posible que desees ver el Preludio numérico , que parece tener relaciones mucho más sensibles entre los diferentes tipos numéricos.