我最近遇到了这个问题并找到了解决方案,但我想知道是否有更好的(或更恰当的)解决方案。
我有一个颜色结构:
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)
答案 0 :(得分:4)
data Rgb = Rgb !Double !Double !Double
而是使用-funbox-strict-fields进行编译,因此可以将组件解压缩为无分配的原始double值。
答案 1 :(得分:3)
不,你不能写类似setSourceRGB(fromRgb rgb)的东西,因为它只会给函数一个参数,所以applyRgb似乎是最好的解决方案。 如果你喜欢这种东西,你也可以使用applyRgb作为中缀函数:
setSource `applyRgb` rgb
如果您经常使用此功能,则可以通过为applyRgb setSource定义名称来使代码更易于阅读。
答案 2 :(得分: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