如何“拆包” Haskell 中的结构

发布于 2024-08-15 05:49:38 字数 1087 浏览 6 评论 0原文

我最近遇到了这个问题并找到了解决方案,但我想知道是否有更好的(或更惯用的)解决方案。

我有一个颜色的结构:

data Rgb = Rgb Double Double Double

并且有一个我想将颜色分量单独传递给的函数,实际上是从开罗传递的:

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

所以我需要以某种方式“解压”这个数据结构,因为 setSourceRGB不采用 Rgb。我找到了两种方法。一种是定义一个函数来应用 Rgb 的内容:

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

然后我可以这样做:

applyRgb setSourceRGB rgb

我想出的另一种方法是使用 case 执行内联 lambda 表达式,这意味着我没有定义一个单独的函数:

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

我对此并不完全满意,但是,以某种方式应用函数只是为了传递一些值似乎并不正确。我希望能够扭转它,并将 Rgb“转换”为 setSourceRGB 的正确类型。不幸的是,在我看来,不可能有一个

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

可以传递给 setSourceRGB 的函数。也许 applyRgb 是最好的解决方案,但我想知道是否有更好的方法可以让我将其表达为:

setSourceRGB (fromRgb rgb)

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

寄意 2024-08-22 05:49:38

顺便说一句,你几乎肯定应该有:

data Rgb = Rgb !Double !Double !Double

相反,并使用 -funbox-strict-fields 进行编译,以便可以将组件解包为免分配的原始双精度值。

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.

伪装你 2024-08-22 05:49:38

不,你不能写像 setSourceRGB (fromRgb rgb) 这样的东西,因为它只会给函数一个参数,所以 applyRgb 似乎是最好的解决方案。
如果你喜欢这种东西,你也可以使用 applyRgb 作为中缀函数:

setSource `applyRgb` rgb

如果你经常使用这个函数,你可以通过为 applyRgb setSource 定义一个名称来使你的代码更容易阅读。

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.

允世 2024-08-22 05:49:38

如果不按照您想出的方式包装函数本身,您就无法将任何内容“解包”到多个参数中。

但是,为了保持一致性,我可能会将助手命名为这样的名称。

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

You can't "unpack" anything into multiple arguments without wrapping the function itself the ways you've figured out.

However, for consistency, I'd probably name the helper something like this.

-- 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文