Що таке комбінатори та як вони застосовуються до програм програмування? (практичне пояснення)


51

Що таке комбінатори?

Я шукаю:

  • практичне пояснення
  • приклади того, як вони використовуються
  • приклади того, як комбінатори покращують якість / загальність коду

Я не шукаю:

  • пояснення комбінаторів, які не допомагають мені виконати роботу (наприклад, Y-комбінатор)

Комбінатори схожі на "прислівники", функції, які приймають функції, потім повертають інші функції. Вони можуть допомогти видалити дублювання коду, оскільки вам не потрібно між змінними. Деякі корисні - двічі (f) = \ x -> f (f (x)), flip (op) -> \ xy -> y op x, (.) Як у (fg) x = f (g (x) )), ($) може допомогти з картою (називається <$> в інфіксі), як у ($ 5) <$> [(+1), (* 2)] = [6, 10], каррі можна використовувати в Lisp / Python / JavaScript для часткового застосування та uncurry можна використовувати для функцій, які потребують записів (кортежів) у Haskell. Коли x |> f = fa, x |> (довжина &&& сума) |> uncurry (/) - середнє значення.
aoeu256

Відповіді:


51

З практичної точки зору комбінатори - це різновиди програмних конструкцій, які дозволяють скласти частинки логіки за цікавими та часто досконалими способами. Зазвичай їх використання залежить від можливості можливості упаковки виконуваного коду в об'єкти, які часто називаються (з історичних причин) лямбда-функціями або лямбда-виразами, але ваш пробіг може змінюватися.

Простий приклад (корисного) комбінатора - той, який приймає дві лямбда-функції без параметрів і створює нову, яка виконує їх послідовно. Фактичний комбінатор виглядає в загальному псевдокоді так:

func in_sequence(first, second):
  lambda ():
    first()
    second()

Найважливіше, що робить цей комбінатор - це анонімна функція (лямбда-функція) у другому рядку; коли ви телефонуєте

a = in_sequence(f, g)

отриманий об'єкт a не є результатом запуску спочатку f (), а потім g (), але це об'єкт, який ви можете зателефонувати пізніше для виконання f () та g () в послідовності:

a() // a is a callable object, i.e. a function without parameters

Ви також можете мати комбінатор, який паралельно виконує два кодові блоки:

func in_parallel(first, second):
  lambda ():
    t1 = start_thread(first)
    t2 = start_thread(second)
    wait(t1)
    wait(t2)

А потім знову,

a = in_parallel(f, g)
a()

Прикольне те, що 'in_parallel' і 'in_sequence' є обома комбінаторами з одним типом / підписом, тобто вони обидва беруть два параметричних об'єкта функцій і повертають новий. Потім ви можете писати такі речі

a = in_sequence(in_parallel(f, g), in_parallel(h, i))

і працює як очікувалося.

В основному комбінатори дозволяють побудувати контрольний потік програми (серед іншого) процедурним та гнучким способом. Наприклад, якщо ви використовуєте in_parallel (..) комбінатор для запуску паралелізму у вашій програмі, ви можете додати налагодження, пов’язане з цим, до реалізації самого in_parallel комбінатора. Пізніше, якщо ви підозрюєте, що у вашій програмі є помилка, пов’язана з паралелізмом, ви можете насправді просто повторити в_parallel:

in_parallel(first, second):
  in_sequence(first, second)

і одним штрихом усі паралельні ділянки перетворені на послідовні!

Комбінатори дуже корисні при правильному використанні.

Однак комбінатор Y не потрібен у реальному житті. Це комбінатор, який дозволяє створювати саморекурсивні функції, і ви можете легко їх створювати на будь-якій сучасній мові без комбінатора Y.


9

Неправильно брендувати Y-комбінатор як щось, що не "допоможе виконати роботу". Я вважав це дуже корисним у багатьох випадках. Найбільш очевидний випадок, коли вам доведеться швидко завантажувати якусь вбудовану інтерпретовану мову. Якщо ви надаєте мінімальний набір примітивів, а саме sequence, select, call, constі closure allocation, вже досить для побудови повного, довільний складного мови. Спеціальної підтримки для рекурсії не потрібно - її можна додати за допомогою комбінатора з фіксованою точкою. Інакше вам знадобляться набагато складніші примітиви.

Ще один очевидний випадок комбінаторів - затуплення. Код, переведений на обчислення SKI, практично не читається. Якщо вам дійсно доведеться придушити реалізацію алгоритму, розгляньте можливість використання комбінаторів, ось приклад .

І, звичайно, комбінатори є важливим інструментом реалізації функціональних мов. Найпростіший підхід (як у прикладі вище) - через SKI або еквівалентне обчислення. Суперкомбінатори використовуються в деяких інших реалізаціях. Ця книга розповідає про це глибоко.

Це жарт , але жарт варто дуже уважно прочитати, оскільки там висвітлено багато прихованих методів та теорій програмування.


1
@MattFenwick, часто виникає потреба у простому вбудованому перекладачі, де ви цього ніколи не очікуєте. Наприклад, у моєму випадку це була мова, яку я повинен був розробити, щоб розширити протокол зв'язку. Простих IPC було недостатньо, тому протокол повинен був бути виконаним.
SK-логіка

@MattFenwick, що стосується вашого запитання: ви можете спробувати написати якийсь код в APL або J. Комбінатори там важливі, тому ви отримаєте уявлення про те, як правильно їх застосовувати. Також читання в стилі без точок може допомогти: en.wikipedia.org/wiki/Tacit_programming
SK-логіка

7

Покопавшись трохи, я знайшов питання StackOverflow, гарне пояснення "Комбінаторів" (Для не математиків), який є близьким двоюрідним братом цього питання. Одна з відповідей вказувала на блог Регінальда Брейтвейта, Homoiconic , який посилається на кілька корисних прикладів комбінаторів у коді (наприклад, K комбінатор , реалізований методом Рубі Object#tap- прочитайте сторінку, щоб ознайомитись із тим, чому це корисно).

Сторінка Вікіпедії про комбінаційну логіку описує комбінаторів більш глобально.


Це стосується другого пункту мого запитання. Дякую за приклад!

1
Цей пост має кілька хороших посилань, але насправді не відповідає безпосередньо на питання. Відповіді мають бути повними самостійно, а за потреби використовувати посилання як посилання.
Aaronaught
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.