2010-08-10 21 views
27

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:Uso excesivo deIntegral en Haskell

import Data.List 

roundDouble 
    :: Double 
    -> Int 
    -> Double 
roundDouble x acc = fromIntegral (round $ x * 10 ** fromIntegral acc)/10 ** fromIntegral acc 

¿Hay alguna manera más fácil de escribir esto? (Sé que puede haber formas más fáciles de redondeo un número y si hay por favor hágamelo saber! Sin embargo, estoy interesado principalmente en la forma de evitar el uso de tantos 'fromIntegrals'.)

Gracias, Ash

Respuesta

24

veces encuentro una función auxiliar útil:

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 

Dónde on es de Data.Function.

+0

No estaba al tanto de 'encendido', ¡gracias por señalarlo! –

+1

Y su variante: http://stackoverflow.com/questions/3453608/overuse-of-fromintegral-in-haskell/3458922#3458922 – sastanin

+6

El tipo de (/.) Es (Integral a, Fraccional b, Integral a1) = > a -> a1 -> b mientras que el tipo de (/) 'on' fromIntegral es (Fraccional b, Integral a) => a -> a -> b. Si necesita el tipo más general, no es apropiado. – Peaker

12

Usted puede usar ^ en lugar de **. ^ toma Integral como su segundo argumento, por lo que no necesita llamar al fromIntegral en el segundo operando. Por lo que su código se convierte en:

roundDouble x acc = fromIntegral ($ redonda x 10^* acc)/10^acc

que sólo tiene un fromIntegral. Y ese que no puede deshacerse como round, naturalmente, devuelve un Integral y no puede realizar una división no entera en un Integral.

6

Tengo un problema similar con el código de cálculo de referencias, donde fromIntegral se usa para convertir CInt a Int. Normalmente defino fI = fromIntegral para hacerlo más fácil. También puede necesitar darle una firma de tipo explícita o usar -XNoMonomorphismRestriction.

Si está haciendo un montón de matemáticas, es posible que desee mirar el Numeric Prelude, que parece tener relaciones mucho más sensatas entre los diferentes tipos numéricos.

+1

que estaba esperando para ver la respuesta que debe definir fI, así que estoy contento de ver a alguien más que escribir. Veré el Preludio numérico, se ve muy útil, ¡gracias! – Ash

+1

Definir fI no es tan ingenioso como algunas otras respuestas, pero tiene la aplicabilidad más amplia en comparación con las otras respuestas hasta el momento. –

4

Otra idea, similar a 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. Por lo que este (/.) permite dividir cualquier par de Real tipos, no necesariamente el mismo, un no necesariamente Integral tipos, 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 cualquier par de Real s, pero sospecho que la división racional y la conversión a/desde Rational no son muy efectivas.

Ahora su ejemplo se convierte en:

roundDouble :: Double -> Int -> Double 
roundDouble x acc = (round $ x * 10^acc) /. (10^acc) 
Cuestiones relacionadas