10

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

我有一个颜色的结构:

data Rgb = Rgb Double Double Double

还有一个函数我想将颜色分量单独传递给,实际上来自开罗:

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

所以我需要以某种方式“解包”这个数据结构,因为setSourceRGB不需要Rgb. 我找到了两种方法。一种是定义一个函数来应用 a 的内容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)
4

3 回答 3

5

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

data Rgb = Rgb !Double !Double !Double

相反,并使用 -funbox-strict-fields 进行编译,因此可以将组件解压缩为无分配的原始双精度值。

于 2009-12-20T04:30:04.073 回答
3

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

setSource `applyRgb` rgb

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

于 2009-12-20T00:46:33.917 回答
2

如果不按照你想出的方式包装函数本身,你就不能将任何东西“解包”成多个参数。

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

-- 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
于 2009-12-20T06:01:29.470 回答