Я хотел бы знать, какие проблемы реальной жизни можно решить с помощью "методов двойственности" в функциональном программировании. Точнее, я хотел бы знать, действительно ли кто-то использовал метод двойственности, как те, которые я приводил ниже, или есть другие интересные примеры. Меня особенно интересовали бы существующие реализации, возможно, в Haskell.
[Поскольку большинство людей, которые будут заинтересованы в этом вопросе, вероятно, знают Haskell, позвольте мне добавить тег Haskell, даже если вопрос совершенно не зависит от языка]
Позвольте мне объяснить, что я подразумеваю под двойственностью (из-за отсутствия лучшего имени) через несколько примеров. Первый - действительные числа. Предположим существование типа Integer и a Rational и определим действительное число как функцию (pardon my Haskell, я не хардкор haskeller)
type Real = Integer -> Rational
такое, что всякий раз, когда x :: Real обозначает действительное число x, x n дает рациональное число, которое находится в пределах 2^(-n) от x.
Теперь можно сделать
(+) :: Real -> Real -> Real
(+) x y n = (x $ n + 1) + (y $ n + 1)
или аналогично для других арифметических операций. Учитывая непрерывную действительную функцию f, можно также вычислить f x, как только можно вычислить модуль непрерывности для f.
Это имеет то преимущество, что можно написать естественный код, а в конце получить результат с требуемым уровнем точности автоматически. Однако сравнивать действительные числа для равенства уже невозможно. Единственное возможное сравнение между x и y - x < y + eps.
Другим примером двойственности является этот вопрос о вероятностных мерах, что вызвало настоящий вопрос в моей голове. Запишем
type Measure a = (a -> Double) -> Double
и определить меры как процедуры интеграции с функциями. В связанном вопросе я показываю, насколько естественно в этой структуре выражать такие понятия, как свертка или pushforward, которые намного сложнее (вычислительно, но и теоретически) определять на уровне плотностей вероятности.
Это позволяет составлять строительные блоки из теории вероятностей и в принципе позволяет строить сложные процедуры Монте-Карло и даже позволяет работать с явной плотностью вероятности (за счет численного интегрирования). Меня особенно интересовала любая попытка создания реальной библиотеки по этой теме.
Еще один пример, который я имею в виду, но еще не совсем формализованный, - это понятие векторных полей (из дифференциальной геометрии), которое можно выразить как операторы дифференцирования. Для этого нужен подходящий тип "гладких вещественнозначных функций", а затем векторное поле выглядит так:
type VectorField = SmoothFunction -> SmoothFunction
такое, что v (f * g) = f * (v g) + g * (v f).
Конечно, описание пучка регулярных функций, например, Haskell, не должно быть легким. Но, делая это, мы могли бы выразить весь материал из дифференциальной геометрии в полностью независимой координате координат и скопировать координаты в самом конце.
Существуют и другие примеры, например. Серия Тейлора обсуждалась в блоге Sigfpe (я не могу найти этот пост), где аналитическая функция имеет следующий тип:
type AnalyticFunction = Double -> Integer -> [Double]
и где f x n возвращает n первые частичные суммы разложения Тейлора f вокруг x. Это позволяет нам беспрепятственно записывать всю арифметику на аналитические функции, в том числе такие вещи, как f / g, где f и g оба могут исчезать в точке (вместе с некоторыми из их производных) или даже f^(-1) (при условии f' не обращается в нуль). В конце вычисляются только необходимые члены промежуточной серии, чтобы получить значение данного выражения.