У меня следующая (простая) структура данных:
struct Work<Input, Output> {
let work: Input -> Output
}
Этот тип представляет работу, которая может занять Input
и превратиться в желаемый Output
. Я пытаюсь понять, соответствует ли эта структура данных некоторым функциональным концепциям, таким как функтор или монада.
Функтор
extension Work {
func map<MoreOutput>(transform: Output -> MoreOutput) -> Work<Input, MoreOutput> {
return Work<Input, MoreOutput> {
return transform(self.work($0))
}
}
}
Насколько мне известно, это кажется правильным. Я могу написать функцию карты, которая может превращать Work<Input, Output>
в Work<Input, MoreOutput>
Монада
Мне сложно придумать определение функции flatMap
(или fold
) для Work
. Единственное, что я могу придумать, это следующее:
extension Work {
func flatMap<MoreOutput>(transform: Work<Output, MoreOutput>) -> Work<Input, MoreOutput> {
return Work<Input, MoreOutput> { input in
return transform.work(self.work(input))
}
}
}
Если вы быстро посмотрите определение flatMap
для Array
, оно будет выглядеть так (упрощенно):
func flatMap(transform: (Element) -> T?) -> [T]
Это функция, аргументом которой является функция, которая преобразует Element
в T
и возвращает Array
. Я не могу придумать способ абстрагировать это до типа Work
.
В другой функциональной книге я нашел следующее общее определение flatMap (для объекта F
типа хранения A
):
func flatMap<B>(f: A -> F<B>) -> F<B>
которое, похоже, реализует flatMap
, отличное от Array
.
Может кто-нибудь объяснить мне эту разницу? И возможно ли вообще определить «правильную» flatMap
функцию на Work
? Или Work
не удовлетворяет свойствам монады?
** Изменить
Спасибо phg за столько полезной информации. Я пробовал дать определение Profunctor:
Делаем Work
a Profunctor
:
extension Work {
func diMap<A, B>(fa: A -> Input, fb: Output -> B) -> Work<A, B> {
return Work<A, B> { arg in
let input = fa(arg)
let output = self.work(input)
return fb(output)
}
}
}
Вам это кажется правильным?