2009-12-20 12 views
10

Ich bin kürzlich auf dieses Problem gestoßen und habe eine Lösung gefunden, aber ich frage mich, ob es bessere (oder einfach idiomatische) Lösungen gibt.Wie man eine Struktur in Haskell "entpackt"

Ich habe eine Struktur für eine Farbe:

data Rgb = Rgb Double Double Double 

Und es gibt eine Funktion, die ich mag die Farbkomponenten passiert einzeln, eigentlich aus Kairo:

setSourceRGB :: Double -> Double -> Double -> Render() 

Also ich brauche diese Datenstruktur irgendwie zu "entpacken", da setSourceRGB keine Rgb einnimmt. Ich habe zwei Wege gefunden. Eine davon ist eine Funktion zu definieren den Inhalt eines Rgb anzuwenden:

applyRgb :: (Double -> Double -> Double -> t) -> Rgb -> t 
applyRgb f (Rgb r g b) = f r g b 

Dann kann ich tun:

applyRgb setSourceRGB rgb 

Eine andere Art und Weise kam ich mit ist ein Inline-Lambda-Ausdruck mit einem Fall zu tun, was bedeutet, dass ich nicht über eine eigene Funktion definieren müssen:

(\z -> (case z of (Rgb r g b) -> setSourceRGB r g b)) rgb 

ich damit aber nicht ganz zufrieden bin, irgendwie eine Funktion der Anwendung nur einige Werte passieren scheint nicht richtig. Ich würde gerne in der Lage sein, es umzudrehen, und "Rgb" in den richtigen Typ für setSourceRGB "konvertieren". Leider scheint es mir, ist, dass es unmöglich ist, eine Funktion zu haben

fromRgb :: Rgb -> Double -> Double -> Double 

, die setSourceRGB geben werden kann. Vielleicht applyRgb ist die beste Lösung, aber ich frage mich, ob es eine bessere Art und Weise, die ich ausdrücken lassen als:

setSourceRGB (fromRgb rgb) 
+3

Was ist mit dem 'Fall .. von'? '(\ (Rgb r g b) -> SetSource r g b) rgb' – ephemient

Antwort

3

Nein, kann man nicht so etwas wie schreiben setSourceRGB (fromRgb rgb), weil es Geben Sie der Funktion nur ein Argument, also scheint applyRgb die beste Lösung zu sein. Wenn Sie diese Art der Sache, können Sie auch applyRgb als Infix-Funktion:

setSource `applyRgb` rgb 

Wenn Sie oft diese Funktion verwenden, kann Ihr Code vereinfachen, indem die Definition einen Namen für applyRgb setSource zu lesen.

4

BTW, sollten Sie mit ziemlicher Sicherheit haben:

data Rgb = Rgb !Double !Double !Double 

statt und kompilieren mit -funbox-strict-Felder, so können die Komponenten in Zuordnung freie primitive Doppel Werte ausgepackt werden.

2

Sie können nichts in mehrere Argumente "entpacken", ohne die Funktion selbst so zu verpacken, wie Sie es herausgefunden haben.

Aber aus Gründen der Konsistenz würde ich den Helfer wahrscheinlich so etwas nennen.

-- from Prelude... 
uncurry :: (a -> b -> c) -> (a, b) -> c 
uncurry f (a, b) = f a b 

-- yours? 
uncurryRgb :: (Double -> Double -> Double -> a) -> Rgb -> a 
uncurryRgb f (Rgb r g b) = f r g b 
+0

Sie sollten die Definition an die Signatur anpassen. Im Moment unterscheiden sich die Fälle. – Martijn

+0

Augh, Tippfehler. Abgesehen von den Rechtschreibunterschieden ist dies die gleiche Definition wie OPs "applyRgb" ... – ephemient