2010-08-10 2 views
27

Immer wenn ich eine Funktion mit Doppel und Ganzzahlen schreibe, finde ich dieses Problem, wo ich ständig "von Integral" überall in meiner Funktion verwenden muss. Zum Beispiel:Überbeanspruchung von fromIntegral in Haskell

import Data.List 

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

Gibt es eine einfachere Möglichkeit, dies zu schreiben? (Ich weiß, es kann einfacher Möglichkeiten, eine Zahl gerundet wird und wenn es lass es mich wissen! Allerdings bin ich in erster Linie daran interessiert, wie mit so vielen ‚fromIntegrals‘ zu vermeiden.)

Danke, Ash

Antwort

24

Manchmal finde ich eine Hilfsfunktion nützlich:

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

Das Helferfunktion auch geschrieben werden kann:

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

Wo on von Data.Function ist.

+0

War nicht bewusst "on", danke für den Hinweis! –

+1

Und seine Variante: http://StackOverflow.com/Questions/3453608/Overuse-of-fromintegral-in-Haskell/3458922#3458922 – sastanin

+6

Der Typ von (/.) Ist (Integral a, Fractional b, Integral a1) = > a -> a1 -> b während der Typ von (/) 'on' von Integral ist (Fractional b, Integral a) => a -> a -> b. Wenn Sie den allgemeineren Typ benötigen, ist on nicht geeignet. – Peaker

12

Sie kann ^ anstelle von ** verwenden. ^ nimmt jedes Integral als zweites Argument, so dass Sie fromIntegral für den zweiten Operanden nicht aufrufen müssen. So Ihr Code wird:

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

die nur ein fromIntegral hat. Und das kann man nicht loswerden, da round natürlich ein Integral zurückgibt und man keine nicht ganzzahlige Division auf einem Integral durchführen kann.

6

Ich habe ein ähnliches Problem mit Marshalling-Code, wobei fromIntegral CInt zu Int konvertiert wird. Normalerweise definiere ich fI = fromIntegral, um es einfacher zu machen. Sie müssen möglicherweise auch eine explizite Typensignatur angeben oder -XNoMonomorphismRestriction verwenden.

Wenn Sie viel Mathe machen, sollten Sie sich vielleicht die Numeric Prelude ansehen, die scheinbar viel sinnvollere Beziehungen zwischen verschiedenen numerischen Typen hat.

+1

Ich habe erwartet, die Antwort sehen zu definieren fI so bin ich froh, es zu sehen, dass jemand anderes schreiben. Ich werde das Numeric Prelude ausprobieren, es sieht sehr nützlich aus, danke! – Ash

+1

Definieren von fI ist nicht so glatt wie einige andere Antworten, aber es hat die breiteste Anwendbarkeit im Vergleich zu den anderen Antworten bisher. –

4

Eine andere Idee, ähnlich wie luqui's. Die meisten meiner Probleme mit fromIntegral beziehen sich auf die Notwendigkeit, Int durch Double oder Double durch Int zu teilen. Also das (/.) erlaubt zwei beliebige Real Typen zu unterteilen, die nicht unbedingt die gleichen, ein nicht unbedingt Integral wie Typen in luqui Lösung:

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

Beispiel:

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

Es für zwei beliebige Real s arbeitet, aber ich vermute, dass rationale Teilung und Umwandlung zu/von Rational nicht sehr effektiv sind.

Jetzt Ihr Beispiel wird:

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