λ -рахунок: Що є найбільш ефективним у представленні функцій пам'яті?


9

Я хотів би порівняти продуктивність функцій, кодованих (Церква / Скотт), з класично кодованими (асемблером / С) структурами даних.

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

Мене цікавлять як поточний алгоритм кодування, який використовують популярні функціональні мови (Haskell, ML), так і найбільш ефективний, якого можна досягти.


Точка Bonus: Чи є така кодування, функції карт кодуються цілі числа в нативні числа ( short, і intт.д. в C). Чи можливо це навіть?


Я ціную ефективність на основі продуктивності. Іншими словами, чим ефективніше кодування, тим менше воно впливає на продуктивність обчислень з функціональними структурами даних.


Усі мої спроби Google провалилися, можливо, я не знаю правильних ключових слів.
Форд О.

Чи можете ви відредагувати питання, щоб уточнити, що ви маєте на увазі під "ефективним"? Ефективний для чого? Коли ви запитуєте про ефективну структуру даних, вам потрібно вказати, які операції ви хочете виконати над структурою даних, оскільки це впливає на вибір структури даних. Або ти маєш на увазі, що кодування є максимально ефективним для простору?
DW

1
Це досить широко. Існує безліч абстрактних машин для обчислення лямбда, які спрямовані на ефективне його виконання (див., Наприклад, SECD, CAM, Krivine's, STG). На додаток до цього, вам слід врахувати закодовані дані Церкви / Скотта, що створює більше проблем. Наприклад, у списках, кодованих Церквою, хвіст має бути O (n) замість O (1). Думаю, я десь прочитав, що існування кодування списків у Системі F з операціями з головою та хвостом O (1) все ще залишається відкритим питанням.
чі

@DW Я говорю про продуктивність / накладні витрати. Наприклад, при ефективному кодуванні відображення списку церкви та списку Хаскелла повинно пройти однаковий час.
Форд О.

Продуктивність для яких операцій? Що ви хочете робити з функціями? Ви хочете оцінити ці функції за деяким значенням? Один раз чи оцінити одну і ту ж функцію за багатьма значеннями? З ними ще щось робити? Ви просто запитуєте, як скласти функцію (написану функціональною мовою), щоб вона могла бути виконана максимально ефективно?
DW

Відповіді:


11

Справа в тому, що насправді не так багато свободи в плані кодування функцій. Ось основні варіанти:

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

  • Закриття: у вас є спосіб представити функцію, можливо, синтаксичне дерево, швидше машинний код. І в цих функціях ви якось посилаєтесь на свої аргументи шляхом посилання. Це може бути зміщення вказівника, це може бути ціле число або індекс De Bruijn, це може бути ім'я. Тоді ви представляєте функцію як закриття : функція "інструкції" (дерево, код тощо) в парі зі структурою даних, що містить усі вільні змінні функції. Коли функція реально застосовується, вона якось знає, як шукати вільні змінні в її структурі даних, використовуючи середовища, арифметику вказівника тощо.

Я впевнений, що є й інші варіанти, але це основні, і я підозрюю, що майже кожен інший варіант буде варіантом або оптимізацією основної структури закриття.

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

Мене цікавлять як поточний алгоритм кодування, який використовують популярні функціональні мови (Haskell, ML)

Я не фахівець, але я на 99% більшість ароматизаторів ML використовую певні варіації закриттів, які я описую, хоча з певними оптимізаціями, ймовірно. Дивіться це на (можливо, застарілу) перспективу.

Haskell робить щось дещо складніше через ледачу оцінку: він використовує безперервне переписування графіків Tagless .

а також у найбільш ефективному, що може бути досягнуто.

Що найефективніше? Не існує жодної реалізації, яка була б найбільш ефективною для всіх вхідних даних, тому ви отримуєте реалізацію, яка є ефективною в середньому, але кожна матиме найкращі результати в різних сценаріях. Тож немає визначеного рейтингу найбільш ефективних або найменш ефективних.

Тут немає ніякої магії. Щоб зберігати функцію, потрібно якось зберігати її вільні значення, інакше ви кодуєте менше інформації, ніж сама функція. Можливо, ви можете оптимізувати деякі вільні значення за допомогою часткової оцінки, але це ризиковано для продуктивності, і ви повинні бути обережними, щоб це завжди зупинялося.

І, можливо, ви можете використовувати якийсь стиснення або розумний алгоритм, щоб отримати космічну ефективність. Але тоді ви або торгуєте часом на простір, або потрапляєте в ситуацію, коли ви оптимізували для одних випадків і сповільнювали для інших.

Ви можете оптимізувати для загального випадку, але те, що є загальним випадком , може змінити мову, область застосування і т. Д. Тип коду, швидкий для відеоігри (хрускіт числа, щільні петлі з великим входом), ймовірно, відрізняється, ніж що швидко для компілятора (обхід дерева, робочі списки тощо).

Бонусний бал: чи існує таке кодування, яке відображає функції закодованих цілих чисел до нативних цілих чисел (коротких, int тощо у C). Чи можливо це навіть?

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

Що ще важливіше, цілі числа займають усі можливі бінарні кодування. Отже, якби лямбда були представлені як їх цілі числа, у вас не було б способу представити лямбди без церкви! Або ви введете прапор, щоб позначити, лямбда - це цифра чи ні, але тоді будь-яка ефективність, яку ви хочете, ймовірно, вийде з вікна.

EDIT: З моменту написання цього запитання мені стало відомо про третій варіант реалізації функцій вищого порядку: дефункціоналізація . Тут кожен виклик функції перетворюється на велику switchзаяву залежно від того, яка абстракція лямбда була надана як функція. Вигода тут полягає в тому, що це ціла трансформація програми: ви не можете складати частини окремо, а потім зв’язувати разом таким чином, оскільки вам потрібно мати повний набір лямбда-абстракцій раніше часу.

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