Что такое банановый сплит и слияние в функциональном программировании?

22

Эти термины упоминаются в моем курсе университета. Быстрый поиск в Google указал мне на некоторые университетские бумаги, но я ищу простое объяснение.

Гаурав Абби
источник
@jozefg: Спасибо за ссылку на ваш пост. Один вопрос по этому поводу. В предложении «Алгебра в этом смысле - это пара объектов C и карта FC → C.», действительно ли C является объектом или, скорее, категорией? Другими словами, я не уверен, обозначает ли F функтор в категории, а F-алгебры являются алгебрами, индуцированными этим функтором, если F является конкретной стрелкой из объекта на себя.
Джорджио
Cэто объект в некоторой категории (скажем CC), Fэто функтор, CC -> CCпоэтому он отображается CCобратно на себя. Теперь F CC -> CCэто просто обычная стрелка в категории CC. Таким образом, Fалгебра - это объект C : CCи стрелка F C -> CвCC
Даниэль Гратцер

Ответы:

4

Хотя 2 ответа уже были предоставлены, я не думаю, что «банановый сплит» здесь уже объяснялся.

Это действительно определено в «Функциональном программировании с использованием бананов, линз, конвертов и колючей проволоки, Эрик Мейер Маартен Фоккинга, Росс Патерсон, 1991»; эту статью трудно читать (для меня) из-за интенсивного использования Squiggol. Тем не менее, «Учебник по универсальности и выразительности сгиба, Грэм Хаттон, 1999» содержит определение, которое легче разобрать:

В качестве простого первого примера использования fold для генерации кортежей, рассмотрим функцию sumlength, которая вычисляет сумму и длину списка чисел:

sumlength :: [Int] → (Int,Int)
sumlength xs = (sum xs, length xs)

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

sumlength = fold (λn (x, y) → (n + x, 1 + y)) (0, 0)

Это определение более эффективно, чем исходное определение, поскольку оно выполняет только один обход списка аргументов, а не два отдельных обхода. Обобщая из этого примера, любую пару применений сгиба к одному и тому же списку всегда можно объединить, чтобы получить единственное применение сгиба, которое генерирует пару, путем обращения к так называемому свойству «бананового разделения» сгиба (Meijer, 1992) , Странное название этого свойства происходит от того факта, что оператор сгиба иногда пишется с использованием скобок (| |), которые напоминают бананы, а оператор сопряжения иногда называется разделением. Следовательно, их комбинация может быть названа банановым расколом!

Клаас ван Шельвен
источник
20

Так что на самом деле это ссылка на статью Мейера и нескольких других под названием « Функциональное программирование с использованием бананов, линз, конвертов и колючей проволоки », основная идея в том, что мы можем взять любой рекурсивный тип данных, например, скажем,

 data List = Cons Int List | Nil

и мы можем выделить рекурсию в переменную типа

 data ListF a = Cons Int a | Nil

причина, по которой я добавил это Fпотому, что теперь это функтор! Это также позволяет нам имитировать списки, но с изюминкой: для создания списков мы должны вложить тип списка

type ThreeList = ListF (ListF (ListF Void)))

Чтобы восстановить наш первоначальный список, мы должны продолжать вкладывать его бесконечно . Это даст нам тип, ListFFгде

  ListF ListFF == ListFF

Для этого определите «тип с фиксированной точкой»

  data Fix f = Fix {unfix :: f (Fix f)}
  type ListFF = Fix ListF

В качестве упражнения вы должны убедиться, что это удовлетворяет нашему уравнению, приведенному выше. Теперь мы наконец можем определить, что такое бананы (катаморфизмы)!

  type ListAlg a = ListF a -> a

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

  cata :: ListAlg a -> ListFF -> a
  cata f = f . fmap (cata f) . unfix

Дальше больше

  cata :: ListAlg a -> ListFF -> a
  cata :: (Either () (Int, a) -> a) -> ListFF -> a
  cata :: (() -> a) -> ((Int, a) -> a) -> ListFF -> a
  cata :: a -> (Int -> a -> a) -> ListFF -> a
  cata :: (Int -> a -> a) -> a -> [Int] -> a

Выглядит знакомо? cataточно так же, как правильные сгибы!

Что действительно интересно, так это то, что мы можем сделать это не только над списками, у любого типа, который определен с помощью этой «фиксированной точки функтора», есть cataи, чтобы вместить их все, мы просто должны ослабить сигнатуру типа.

  cata :: (f a -> a) -> Fix f -> a

Это на самом деле вдохновлено частью теории категорий, о которой я писал , но это мясо стороны Haskell.

Даниэль Гратцер
источник
2
Стоит ли упоминать, что бананы - это скобки (| |), которые используются в оригинальной статье для определения cata
jk.
7

Хотя jozefg дал ответ, я не уверен, что он ответил на вопрос. «Закон слияния» объясняется в следующей статье:

Учебник об универсальности и выразительности складки, GRAHAM HUTTON, 1999

В основном это говорит о том, что при некоторых условиях вы можете комбинировать («плавить») композицию функции и складывать ее в одну складку, поэтому в основном

ч · раз gw = сложить fv

Условиями этого равенства являются

hw = v
h (gxy) = fx (hy)

«Банановый сплит» или «Банановый сплит закон» из статьи

Функциональное программирование с помощью бананов, линз, конвертов и колючей проволоки, Эрик Мейер Маартен Фоккинга, Росс Патерсон, 1991

К сожалению, эту статью очень трудно расшифровать, так как она использует формализм Берда-Меертенса, поэтому я не мог понять, чего она стоит. Насколько я понял, «закон о банановом разделении» говорит, что если у вас есть 2 сгиба, работающие с одним и тем же аргументом, они могут быть объединены в один сгиб.

Джеки
источник