2010-08-10 11 views
27

Zawsze, gdy piszę funkcję za pomocą podwójnych i całkowitych liczb, uważam, że jest to problem, w którym ciągle muszę używać "fromIntegral" wszędzie w mojej funkcji. Na przykład:Nadużywanie aplikacji fromIntegral w Haskell

import Data.List 

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

Czy istnieje prostszy sposób na zapisanie tego? (Wiem, że nie może być prostsze sposoby zaokrąglania numer i jeśli istnieją proszę dać mi znać! Jednak jestem zainteresowana głównie w jaki sposób unikać tak wiele „fromIntegrals”).

Dzięki, Ash

Odpowiedz

24

Czasami znajdę funkcję pomocnika przydatne:

roundDouble x acc = (round $ x * 10^acc) /. (10^acc) 
    where 
    x /. y = fromIntegral x/fromIntegral y 

To funkcja pomocnika może być również napisane:

(/.) = (/) `on` fromIntegral 

Gdzie on wynosi od Data.Function.

+0

Nie wiedział o "włączeniu", dzięki za wskazanie go! –

+1

I jego wariant: http://stackoverflow.com/questions/3453608/overuse-of-integrated-in-haskell/3458922#3458922 – sastanin

+6

Typ (/.) To (całkowy a, ułamkowy b, całkowy a1) = > a -> a1 -> b podczas gdy typ (/) 'on' fromIntegral to (ułamkowe b, całkowe a) => a -> a -> b. Jeśli potrzebujesz bardziej ogólnego typu, włączenie nie jest właściwe. – Peaker

12

Ty można użyć ^ zamiast **. ^ przyjmuje dowolny całkowy jako drugi argument, więc nie trzeba wywoływać fromIntegral w drugim operandzie. Tak więc staje się kod:

roundDouble x acc = fromIntegral (okrągłe $ x * 10^acc)/10^acc

który ma tylko jeden fromIntegral. I tego nie można się pozbyć, ponieważ round w naturalny sposób zwraca całkę i nie można wykonać niecałkowitego podziału na całkę.

6

Mam podobny problem z kodowaniem marshaling, gdzie fromIntegral służy do konwersji CInt na Int. Zwykle definiuję fI = fromIntegral, aby było łatwiej. Może być również konieczne nadanie mu jawnego podpisu typu lub użycie opcji -XNoMonomorphismRestriction.

Jeśli robisz dużo matematyki, możesz spojrzeć na Numeric Prelude, która wydaje się mieć dużo bardziej sensowne relacje między różnymi typami liczbowymi.

+1

Spodziewałem się zobaczyć odpowiedź do definiowania fI więc cieszę się zobaczyć kogoś innego pisać. Sprawdzę Preludium numeryczne, wygląda bardzo użytecznie, dzięki! – Ash

+1

Definiowanie fI nie jest tak proste jak niektóre inne odpowiedzi, ale ma ono najszersze zastosowanie w porównaniu do innych dotychczasowych odpowiedzi. –

4

Inny pomysł, podobny do luqui's. Większość moich problemów z fromIntegral wiąże się z koniecznością podziału Int przez Double lub Double przez Int. Więc to (/.) pozwala podzielić dwie Real wszelkich typów, nie koniecznie taka sama, an niekoniecznie Integral typy jak w roztworze luqui za:

(/.) :: (Real a, Real b, Fractional c) => a -> b -> c 
(/.) x y = fromRational $ (toRational x)/(toRational y) 

Przykład:

ghci> let (a,b,c) = (2::Int, 3::Double, 5::Int) 
ghci> (b/.a, c/.a, a/.c) 
(1.5,2.5,0.4) 

To działa dla dowolnych dwóch Real s, ale podejrzewam, że racjonalny podział i konwersja do/z Rational nie są zbyt skuteczne.

Teraz Twój przykład postać:

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