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.
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
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
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