Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to "unpack" a structure in haskell

I recently came across this problem and found a solution but I'm wondering if there are better (or just more idiomatic) solutions.

I have a structure for a colour:

data Rgb = Rgb Double Double Double

And there is a function I'd like to pass the colour components to individually, actually from Cairo:

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

So I need to "unpack" this data structure somehow, since setSourceRGB doesn't take an Rgb. I found two ways. One is to define a function to apply the contents of an Rgb:

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

Then I can do:

applyRgb setSourceRGB rgb

Another way I came up with is to do an inline lambda expression with a case, which means I don't have to define a separate function:

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

I'm not completely happy with this however, somehow applying a function just to pass some values doesn't seem right. I'd like to be able to turn it around, and "convert" the Rgb to the right type for setSourceRGB. Unfortunately it seems to me that's it's impossible to have a function

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

that can be passed to setSourceRGB. Perhaps applyRgb is the best solution, but I'm wondering if there's some better way that will let me express it as:

setSourceRGB (fromRgb rgb)
like image 984
Steve Avatar asked Dec 20 '09 00:12

Steve


2 Answers

BTW, you should almost certainly have:

data Rgb = Rgb !Double !Double !Double

instead, and compile with -funbox-strict-fields, so the components can be unpacked into allocation-free primitive double values.

like image 171
Don Stewart Avatar answered Sep 29 '22 21:09

Don Stewart


No, you can't write something like setSourceRGB (fromRgb rgb), because it will just give one argument to the function, so applyRgb seems like the best solution. If you like this sort of thing, you can also use applyRgb as an infix function :

setSource `applyRgb` rgb

If you often use this function, your can make your code easier to read by defining a name for applyRgb setSource.

like image 45
gnomnain Avatar answered Sep 29 '22 19:09

gnomnain