2016-10-30 2 views
3

Haskell Anfänger (und neu in der Programmierung im Allgemeinen), ich versuche, einen Code zu schreiben, der RGB-Farbwerte in CMYK konvertiert. Ich habe als Referenz hier gesucht um, und danach habe ich es geschafft, dies zu schreiben:RGB zu CMYK, Haskell

rgb2cmyk :: Int Int Int -> (Float,Float,Float,Float) 
rgb2cmyk r g b = ((w - (r/255))/w, (w - (g/255))/w, (w -(b/255))/w, 1 - w) 
      where w = max (r/255, g/255, b/255) 

Beim Versuch, das Modul in GHCi ich folgendes erhalten zu laden:

‘Int’ is applied to too many type arguments 
In the type signature for ‘rgb2cmyk’: 
    rgb2cmyk :: Int Int Int -> (Float, Float, Float, Float) 
Failed, modules loaded: none. 

Ich verstehe nicht wirklich Was ich falsch gemacht habe, kann mir jemand Anleitung geben? Vielen Dank.

+0

Beachten Sie, dass die Argumente 'Int', aber die Ergebnisse' Float' ein Problem ergeben, das nicht mit dem aktuellen Fehler zusammenhängt: die numerischen Typen müssen konvertiert werden; Haskell verlangt immer, dass dies explizit gemacht wird. Verwenden Sie dafür ['fromIntegral'] (http://hackage.haskell.org/package/base-4.9.0.0/docs/Prelude.html#v:fromIntegral). – leftaroundabout

+0

Können Sie mir bitte zeigen, wie genau das gemacht wird? Muss ich die Signatur ändern? Ich habe einfach von Integral wie zum Beispiel hinzugefügt: ((w - (fromIntegral r/255))/w, aber das schien es nicht funktionieren zu lassen. – Rad

+0

Sie müssen die Konvertierung vor allen Abteilungen vornehmen. Ich würde zuerst alle rgb-Kanäle konvertieren, bevor irgendwelche Berechnungen durchgeführt werden; Eine Möglichkeit, dies zu tun, ist die Übereinstimmung von "Vorargumenten" 'rgb2cmyk r 'g' b '= ...' und die Verwendung von 'where [r, g, b] = [fromIntegral c/255 | c <- [r ', g', b ']] ', um" r "," g "und" b "in Fließkomma- und Bereichsnormalisierungsform zu erhalten. – leftaroundabout

Antwort

3

Haskell Funktionen mit mehreren Argumenten arbeiten in einem etwas seltsamen (aber, nachdem Sie sich daran gewöhnt haben, sehr nützlich) Weg. rgb2cmyk r g b = ... ist eigentlich nur eine kurze Möglichkeit, die lambda expressionrgb2cmyk = \r -> \g -> \b -> ... zu schreiben, d. H. Das ist eigentlich eine Verschachtelung von drei Funktionen, von denen jede nur ein einziges Argument dauert. Daraus ergibt sich die Art dieser Funktion ist wirklich

rgb2cmyk :: Int -> (Int -> (Int -> ...)) 

Da dieses Muster in Haskell so üblich ist, werden die Parsing-Regeln definiert, so dass Sie diese Klammern weglassen. Die Signatur, die Sie definieren möchten, ist also eigentlich

rgb2cmyk :: Int -> Int -> Int -> (Float,Float,Float,Float) 

Alternativ könnten Sie es auch

rgb2cmyk :: (Int,Int,Int) -> (Float,Float,Float,Float) 
rgb2cmyk (r,g,b) = ... 

In diesem Fall rgb2cmyk hat nur ein einziges Argument

machen, aber das hat eine Verbindung Art. Ich würde argumentieren, dass dies für diese spezielle Funktion tatsächlich sinnvoller ist als drei separate Argumente für jede Farbe .

Aber Int Int Int ist keine Verbindung Typ von drei ganzen Zahlen bedeutet es etwas ganz anderes: Es interpretiert die ersten Int als Typ-Level-Funktion, die auf zwei anderen Int s angewandt wird. Das macht keinen Sinn, Int ist keine Typ-Level-Funktion. Dies ist, was der Compilerfehler Ihnen sagt.


In der Tat, sollten Sie wahrscheinlich nicht Tupeln verwenden, aber in geeigneter Weise genannt Satzarten:

data RGB = RGB {_RChannel, _GChannel, _BChannel :: !Int} 
data CMYK = CMYK {_CChannel, _MChannel, _YChannel, _KChannel :: !Float} 

Hier macht die ! die einzelnen Kanäle strengen: es doesn‘ Es macht wirklich viel Sinn, alle Farbkanäle einzeln auszuwerten und effizienter zu machen. Wenn Sie die Erweiterung -XUnboxStrictFields aktivieren, kompiliert GHC auch strikte Datensätze zu einer viel mehr Speicher-effizienten Struktur.

+0

Ich habe vergessen (oder wahrscheinlicher, nie realisiert), dass Sie mehrere Felder mit einem gemeinsamen Typ wie diesem angeben können. – chepner

+0

Das Unboxing strikter Felder ist ein Optimierungsflag, keine Sprachenerweiterung, und es ist standardmäßig aktiviert (wenn Optimierungen aktiviert sind) für Felder, die nur ein einzelnes Wort verwenden, wenn sie nicht gerahmt sind. –