Вопрос

Недавно я столкнулся с этой проблемой и нашел решение, но мне интересно, есть ли лучшие (или просто более идиоматические) решения.

У меня есть структура для цвета:

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

Другой способ, который я придумал, — это использовать встроенное лямбда-выражение с регистром, что означает, что мне не нужно определять отдельную функцию:

(\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)
Это было полезно?

Решение

Нет, вы не можете написать что-то вроде setSourceRGB (fromRgb rgb), потому что это даст функции только один аргумент, поэтому applyRgb кажется лучшим решением.Если вам нравятся подобные вещи, вы также можете использовать applyRgb в качестве инфиксной функции:

setSource `applyRgb` rgb

Если вы часто используете эту функцию, вы можете облегчить чтение кода, определив имя для applyRgb setSource.

Другие советы

Кстати, у вас почти наверняка должно быть:

data Rgb = Rgb !Double !Double !Double

вместо этого и скомпилируйте с -funbox-strict-fields, чтобы компоненты можно было распаковать в примитивные двойные значения без выделения.

Вы не можете «распаковать» что-либо в несколько аргументов, не обернув саму функцию способами, которые вы выяснили.

Однако для последовательности я бы, наверное, назвал помощника примерно так.

-- 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top