Лямбда-числення

Матеріал з testwiki
Перейти до навігації Перейти до пошуку

Ля́мбда-чи́слення, або λ-чи́слення — формальна система, що використовується в теоретичній кібернетиці для дослідження визначення функції, застосування функції, та рекурсії. Це числення було запропоноване Алонсо Черчем та Стівеном Кліні в 1930-ті роки, як частина більшої спроби розробити базис математики на основі функцій, а не множин (задля уникнення таких перешкод, як Парадокс Рассела). Однак Шаблон:Нп демонструє, що лямбда-числення не здатне уникнути теоретико-множинних парадоксів. Незважаючи на це, лямбда-числення виявилось зручним інструментом в дослідженні обчислюваності функцій, та лягло в основу парадигми функціонального програмування[1].

Лямбда-числення можна розглядати як ідеалізовану, мінімалістичну мову програмування, у цьому сенсі лямбда-числення подібне до машини Тюрінга, іншої мінімалістичної абстракції, здатної визначати будь-який алгоритм. Відмінність між ними полягає в тому, що лямбда-числення відповідає функціональній парадигмі визначення алгоритмів, а машина Тюрінга, натомість — імперативній. Тобто, машина Тюрінга має певний «стан» — перелік символів, що можуть змінюватись із кожною наступною інструкцією. На відміну від цього, лямбда-числення уникає станів, воно має справу з функціями, котрі отримують значення параметрів та повертають результати обчислень (можливо, інші функції), але не спричиняють до зміни вхідних даних (сталість).

Ядро λ-числення ґрунтується трохи більше ніж на визначені змінних, області видимості змінних та впорядкованому заміщенні змінних виразами. λ-числення є замкненою мовою, тобто семантика мови може бути визначена на основі еквівалентності виразів (або термів) самої мови[2].

Визначення лямбда-виразів

Множину λ-виразів можна визначити індуктивно таким чином[3]:

  • будь-яка змінна — це λ-вираз;
  • λ-абстракція λx.M — це λ-вираз, якщо x — це змінна, а M — λ-вираз;
  • аплікація MN — це λ-вираз, якщо M та N — λ-вирази.

Інтуїтивно, абстракції відповідають функціям, а аплікації їх застосуванню. Особливістю лямбда-числення є те, що аргументи «функцій», визначених таким чином, — це теж функції. Наприклад, λx.x — це λ-вираз, що відповідає функції ідентичності, а λx.xM — це аплікація цієї функції до M, у випадку коли M — це теж λ-вираз.

На цій множині ми визначаємо відношення β, що називається бета-редукція:

(λxM)NβM[x:=N],

де M[x:=N] означає, що вираз N підставляється всюди замість змінної x у виразі M.

Тоді, у попередньому прикладі матимемо: (λx.x)Mβx[x:=M]=M. Як і очікувано, застосування функції ідентичності до певного виразу повертає цей вираз.

Ремарка: Як і у випадку логіки першого порядку, важливо слідкувати за вільними змінними, коли йдеться про абстракцію та підстановки.

λ-вирази не такі складні, якими здаються на перший погляд. Просто треба звикнути до префіксної форми запису. Більше немає ні інфіксних (+,), ні постфіксних (x2) операцій. Крім того, аргументи функцій просто записуються в список після функції, розділені пропуском. Тому всюди, де математики пишуть sin(x), в лямбда-численні пишуть sinx. Так само замість x + y пишуть + x y, а замість x2 — * x x.

Хоча дужки таки не пропадають. Вони використовуються для групування. Наприклад, математичний вираз sin(x)+4 в лямбда-численні записується як + (sinx) 4.

Якщо вираз містить змінну, то він може описувати функцію, як залежність свого значення від значення змінної, наприклад f(x)=3x. Лямбда-числення має спеціальний синтаксис, який не зобов'язує задавати ім'я функції (як для f). Для запису функції переводимо вираз в правій частині в префіксну форму (* 3 x), і дописуємо спереду «λx.». Отримуємо λx. * 3 x. Грецька літера λ має роль, подібну до тої що має слово «function» в деяких мовах програмування. Вона вказує читачу що змінна після неї — не частина виразу, а формальний параметр функції, що задається. Крапка після параметра позначає початок тіла функції.

Мова Приклад
Лямбда-числення λx.* 3 x
Pascal
function f(x: integer): integer  begin f:= 3*x end;
(не зовсім лямбда-вираз, оскільки є назва функції, але суть та ж)
Lisp
(lambda (x) (* 3 x))
Python
lambda x: x*3
C++11
 [](int x) { return x * 3 }
Swift
  { return $0 * 3 }

Щоб застосувати створену функцію до якихось аргументів, її просто підставляють в вираз, наприклад так: (λx.* 3 x)4. Дужки навколо функції потрібні, щоб чітко знати де вона закінчується. Якби ми написали λx.* 3 x4, то це могло б сприйматись як функція, що повертає 3*x*4==12x, якщо * — тернарний оператор, або як синтаксична помилка, якщо * — завжди бінарне.

Для зручності ми можемо позначити нашу функцію якоюсь буквою:

Fλx.* 3 x

і потім просто писати F4.

Залишилось розглянути ще один цікавий випадок:

Nλy.(λx.* y x)

якщо передати N 3, то вона поверне нашу стару функцію λx.* 3 x. Тобто N3 працює як F, якій ми можемо передати наприклад 4, записавши це як N 3 4. Або, ми можемо розглядати її як функцію від двох аргументів.

Можна записати це в скороченій формі, без дужок:

λy.λx.* x y

Чи ще коротше:

λy x.* x y

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

Нотація λ-числення

Функція n змінних v1,,vn в λ-численні позначається так:

f=λv1vn.e0.

Символ f в лівій частині цього рівняння задає назву функції, (або ідентифікатор), за яким можна посилатись на цю функцію в інших виразах. Вираз у правій частині рівняння визначає абстракцію змінних v1,,vn від виразу e0, котрий називається тілом абстракції. Конструкція λv1,,vn є абстрактором появи вільних змінних v1,,vn в тілі функції e0.

Застосування функції (або абстракції) з назвою f до виразу з r аргументами e1,,er позначається:

(fe1er)=(λv1vn.e0e1er),

Де r не обов'язково має дорівнювати n.

Особливим випадком є застосування абстракції до абстрагованих змінних, що повертає тіло абстракції:

(λv1vn.e0v1vn)=e0.

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

f=λv1vn.e0λv1.λv2λvn.e0.

Використовуючи цю нотацію, застосування n-арної абстракції до r аргументів, наведене вище, матиме такий вигляд:

(fe1er)=(((fe1)e2)er).

Такий підхід скорочує побудову виразів λ-числення до наступних синтаксичних правил:

e=sv|c|(e0e1)|λv.e0.

Тобто, λ-вираз це: або змінна, що позначається v, константа c, застосування λ-виразу e0 до λ-виразу e1, або абстракція змінної v від λ-виразу e0 відповідно.

λ-числення називається чистим, якщо множина констант порожня. В іншому випадку числення називається аплікативним.

Див. також

Примітки

Шаблон:Reflist

Література

Шаблон:Comp-stub Шаблон:Math-stub

Шаблон:Математична логіка

  1. Henk Barendregt 1997
  2. Kluge 2005, сторінка 51.
  3. M.H. Sorensen and P. Urzyczyn «Lectures on the Curry-Howard Isomorphism» (2006)