Комбинаторы — это просто!: различия между версиями

Содержимое удалено Содержимое добавлено
м Вставлено длынное тире
Соединены строка в абзацах, картинки заменены формулами, вставлены ссылки, прочие правки.
Строка 1:
:''Исходный вариант статьи (Р. В. Душкин, «Комбинаторы? — Это просто!») опубликован в [[Журнал «Потенциал»|журнале «Потенциал»]], № 7, 2006.''
 
Данная статья описывает основы [[w:Комбинаторная логика|комбинаторной логики]] - [[w:Математика|математической науки]] о [[w:Вычисление|вычислениях]], в которой любые объекты изучения выражаются при помощи двух базовых объектов <math>S</math> и <math>K</math>, называемых [[w:Комбинатор|комбинаторами]], и одной операции над ними - операции применения одного комбинатора к другому.
 
== Введение ==
 
Комбинаторная логика (от слова «комбинатор», а не «[[w:Комбинаторика|комбинаторика]]») — это направление в [[w:Математическая логика|математической логике]], разработанное в первой половине XX века логиками [[w:Шёнфинкель, Мозес|Мозесом Шёнфинкелем]] и [[w:Карри, Хаскелл|Хаскеллом Карри]] в качестве науки о вычислительных процессах. Хотя первоначально этот вид логики претендовал только на то, чтобы удалить из [[w:Высказывание (логика)|логических высказываний]] переменные, через некоторое время в [[w:Информатика|информатике]] были получены прикладные результаты, показавшие, что комбинаторную логику можно использовать для проведения вычислений.
 
На комбинаторную логику можно смотреть как на некоторое упрощение [[w:Лямбда-исчисление|λ-исчисления]] {{ref|lambda}}, в котором нет символа λ, а все функциональные абстракции представлены ограниченным набором символов, называемых «комбинаторами». Такие комбинаторы не содержат [[w:Переменная|переменных]], являются [[w:Функция высшего порядка|функциями высшего порядка]], то есть в качестве аргументов могут принимать на вход другие [[w:Функция (математика)|функции]], а также описывают определённые правила преобразования
Комбинаторная логика (от слова «комбинатор», а не «комбинаторика») &mdash; это направление в математической логике, разработанное в первой половине XX века логиками Мозесом Шёнфинкелем и Хаскеллом Карри в качестве науки о вычислительных процессах. Хотя первоначально этот вид логики претендовал только на то, чтобы удалить из логических высказываний переменные, через некоторое время в информатике были получены прикладные результаты, показавшие, что комбинаторную логику можно использовать для проведения вычислений.
 
На комбинаторную логику можно смотреть как на некоторое упрощение
<math>\lambda</math>-исчисления {{ref|lambda}}, в котором
нет символа <math>\lambda</math>, а все функциональные абстракции представлены
ограниченным набором символов, называемых «комбинаторами». Такие
комбинаторы не содержат переменных, являются функциями высшего
порядка, т.&nbsp;е. в качестве аргументов могут принимать на вход другие
функции, а также описывают определённые правила преобразования
объектов, поданных им на вход в качестве аргументов.
 
Другими словами, комбинаторная логика&nbsp;&mdash; это формализм для представления функциональных зависимостей между входными и выходными данными. В этом формализме зависимости и сами данные записываются в одном и том же весьма ограниченном [[w:Алфавит (математика)|алфавите]].
представления функциональных зависимостей между входными и выходными
данными. В этом формализме зависимости и сами данные записываются в одном и том же
весьма ограниченном алфавите.
 
==Формальная теория==
Для того, чтобы не быть голословным, необходимо чётко описать
базовые объекты комбинаторной логики, которые участвуют в формальной
системе, определяющей саму комбинаторную логику. Согласно
математической практике, необходимо определить следующие элементы
формальной системы:
 
#Алфавит.
#Утверждения (множество правильно построенных формул).
#Аксиомы.
#Правила вывода.
 
== Формальная теория ==
 
Для того, чтобы не быть голословным, необходимо чётко описать базовые объекты комбинаторной логики, которые участвуют в [[w:Формальная теория|формальной системе]], определяющей саму комбинаторную логику. Согласно математической практике, необходимо определить следующие элементы формальной системы:
Под алфавитом понимается набор символов, допустимых в нотации
записей термов в комбинаторной логике. В общем виде при помощи
нотации комбинаторной логики можно записывать объекты нескольких
типов &mdash; константы, переменные, термы и специальные знаки.
 
# Алфавит.
Константы обозначаются малыми буквами латинского алфавита, возможно
# Утверждения (множество правильно построенных [[w:Математическая формула|формул]]).
с индексами. Обычно для обозначения констант берутся символы с
# [[w:Аксиома|Аксиомы]].
начала алфавита. Переменные обозначаются также малыми буквами,
# Правила вывода.
возможно, с индексами, но при этом они обычно выбираются с конца
алфавита: <math>c_{1}</math>, <math>c_{2}</math> &mdash; константы, <math>x</math>, <math>y</math> &mdash; переменные.
 
Под алфавитом понимается набор символов, допустимых в [[w:Математическая нотация|нотации]] записей [[w:Терм (логика)|термов]] в комбинаторной логике. В общем виде при помощи нотации комбинаторной логики можно записывать объекты нескольких
Однако для выделения константных объектов иногда будет
типов — [[w:Математическая константа|константы]], переменные, термы и специальные знаки.
использоваться иной способ записи. Такой способ заключается в
выделении наименований констант полужирным начертанием &mdash; эта
запись будет использоваться, если наименование константы состоит
более чем из одного символа: '''if''', '''true''',
'''pair''' и др.
 
Константы обозначаются малыми буквами [[w:Латинский алфавит|латинского алфавита]], возможно с индексами. Обычно для обозначения констант берутся символы с начала алфавита. Переменные обозначаются также малыми буквами, возможно, с индексами, но при этом они обычно выбираются с конца алфавита: <math>c_1</math>, <math>c_2</math> — константы, <math>x</math>, <math>y</math> — переменные.
 
Однако для выделения константных объектов иногда будет использоваться иной способ записи. Такой способ заключается в выделении наименований констант полужирным начертанием — эта
Комбинаторные термы (или просто «выражения») будут обозначаться
запись будет использоваться, если наименование константы состоит более чем из одного символа: <math>\mathbf{if}</math>, <math>\mathbf{true}</math>, <math>\mathbf{pair}</math> и другие.
заглавными буквами латинского алфавита, возможно также с индексами:
<math>M</math>, <math>N</math> и т.&nbsp;д.
 
Комбинаторные термы (или просто «выражения») будут обозначаться заглавными буквами латинского алфавита, возможно также с индексами: <math>M</math>, <math>N</math> и так далее.
Из специальных символов в комбинаторной логике используется всего
три: это скобки «(» и «)», а также знак равенства (<math>=</math>).
Последний обозначает отношение конвертируемости &mdash; возможность преобразования одного
терма в другой. С точки зрения вычислительных процессов, отношение конвертируемости
определяет сам процесс вычисления значения функции, представленной
комбинаторным термом.
 
Из специальных символов в комбинаторной логике используется всего три: это скобки «(» и «)», а также знак равенства (<math>=</math>). Последний обозначает отношение конвертируемости — возможность преобразования одного терма в другой. С точки зрения вычислительных процессов, отношение конвертируемости определяет сам процесс вычисления значения функции, представленной комбинаторным термом.
 
Множество правильно построенных формул в комбинаторной логике выглядит очень просто. Его составляют выражения вида <math>\{M = N\}</math>, где <math>M</math> и <math>N</math> — комбинаторные термы. При этом сами комбинаторные термы строятся по [[w:Математическая индукция|индукции]]:
выглядит очень просто. Его составляют выражения вида {<math>M = N</math>},
где <math>M</math> и <math>N</math> &mdash; комбинаторные термы. При этом сами комбинаторные
термы строятся по индукции:
 
1) {если <math>c</math> &mdash; константа, то <math>c</math> &mdash; комбинаторный терм;}
 
2) {если <math>x</math> &mdash; переменная, то <math>x</math> &mdash; комбинаторный терм;}
 
3) {если <math>M</math> и <math>N</math> &mdash; комбинаторные термы, то <math>(MN)</math> &mdash; комбинаторный терм;}
 
4) {других комбинаторных термов нет.}
 
В этом индуктивном определении выражение <math>(MN)</math> обозначает операцию аппликации, единственную операцию комбинаторной логики. Аппликация описывает применение функции (в данном примере — терм <math>M</math>) к её аргументу или аргументам (в данном примере — терм <math>N</math>).
аппликации, единственную операцию комбинаторной логики. Аппликация
описывает применение функции (в данном примере &mdash; терм <math>M</math>) к её
аргументу или аргументам (в данном примере &mdash; терм <math>N</math>).
 
Как видно, создание комбинаторных термов повлечёт за собой лавинообразное внедрение в запись таких термов скобок. Для того, чтобы уменьшить количество скобок в записях комбинаторных термов, вводятся соглашения о скобках, которые заключаются в том, что пропущенные скобки восстанавливаются по ассоциативности влево:
 
<math>XY = (XY)</math>
Как видно, создание комбинаторных термов повлечёт за собой
лавинообразное внедрение в запись таких термов скобок. Для того,
чтобы уменьшить количество скобок в записях комбинаторных термов,
вводятся соглашения о скобках, которые заключаются в том, что
пропущенные скобки восстанавливаются по ассоциативности влево:
 
<math>\begin{matrix}XY = (XY) \\XYZ = ((XY)Z)\end{matrix}</math>
 
В качестве аксиом, входящих в множество правильно построенных формул, обычно выделяются следующие:
 
{| width = "50%"
В качестве аксиом, входящих в множество правильно построенных
|<math>\mathbf I\, x = x</math> || align = "right" | (I)
формул, обычно выделяются следующие:
 
 
 
{|width=50%
|'''I'''x = x
|'''(I)'''
|-
|<math>\mathbf K\, xy = x</math> || align = "right" | (K)
|'''K'''xy = x
|'''(K)'''
|-
|'''<math>\mathbf S'''\, xyz = xz(yz)</math> || align = "right" | (S)
|'''(S)'''
|}
 
Данные аксиомы не надо доказывать, их наличие просто постулируется. Эти аксиомы определяют три базовых комбинатора, использующихся для вывода (вычислений) новых комбинаторов. Традиционно базис <math>\mathbf S</math>, <math>\mathbf K</math>, <math>\mathbf I</math> является тем набором первоначальных комбинаторов, через который выражаются все прочие комбинаторы. Однако это не минимальный базис, ибо наличие комбинатора <math>\mathbf I</math> в нём не обязательно, так как его можно выразить через комбинаторы <math>\mathbf S</math> и <math>\mathbf K</math>:
 
<math>\mathbf{SKK}\, x\; \stackrel\mathbf S=\; \mathbf K\, x (\mathbf K\, x)\; \stackrel\mathbf K=\; x \equiv \mathbf I\, x</math>
Данные аксиомы не надо доказывать, их наличие просто постулируется.
Эти аксиомы определяют три базовых комбинатора, использующихся для
вывода (вычислений) новых комбинаторов. Традиционно базис '''S,K,I'''
является тем набором первоначальных комбинаторов, через который
выражаются все прочие комбинаторы. Однако это не минимальный базис,
ибо наличие комбинатора '''I''' не обязательно в нём, т.&nbsp;к.
его можно выразить через комбинаторы '''S''' и '''K''':
 
 
[[Изображение:SKK.jpg]]
 
Другими словами, комбинаторный базис &mdash; это набор комбинаторов,
через которые при помощи отношения конвертируемости (<math>=</math>) можно
выразить все остальные комбинаторы. Минимальным комбинаторным
базисом является набор из комбинаторов '''S''' и
'''K''', но обычно его дополняют комбинатором '''I'''
для упрощения записи выражаемых комбинаторных термов. Однако
разнообразных базисов может быть бесчисленное множество, и разные
исследователи вводили разные базисы для своих целей. В следующем
разделе будут рассмотрены некоторые примеры таких базисов.
 
Другими словами, комбинаторный базис — это набор комбинаторов, через которые при помощи отношения конвертируемости (<math>=</math>) можно выразить все остальные комбинаторы. Минимальным комбинаторным базисом является набор из комбинаторов <math>\mathbf S</math> и
Остаётся рассмотреть правила вывода, которые используются в рамках
<math>\mathbf K</math>, но обычно его дополняют комбинатором <math>\mathbf I</math> для упрощения записи выражаемых комбинаторных термов. Однако разнообразных базисов может быть бесчисленное множество, и разные исследователи вводили разные базисы для своих целей. В следующем разделе будут рассмотрены некоторые примеры таких базисов.
комбинаторной логики для преобразования одних термов в другие и
описывают отношение конвертируемости (<math>=</math>). Данные правила вывода
по своей сути описывают это отношение, задавая его характеристики.
 
Остаётся рассмотреть правила вывода, которые используются в рамках комбинаторной логики для преобразования одних термов в другие и описывают отношение конвертируемости (<math>=</math>). Данные правила вывода по своей сути описывают это отношение, задавая его характеристики.
 
{| width = "50%"
| <math>a = a</math> || aligh = "right" | {ρ}
| a = a
|{<math>\rho</math>}
|-
| <math>(a = b) <math>\Rightarrow</math> (b = a)</math> || aligh = "right" | {σ}
|{<math>\sigma</math>}
|-
| <math>(a = b) <math>\wedge</math>land (b = c) <math>\Rightarrow (a = c)</math> (a|| aligh = c)"right" | {τ}
|{<math>\tau</math>}
|-
| <math>(a = b) <math>\Rightarrow</math> (ca = cb)</math> || aligh = "right" | {μ}
|{<math>\mu</math>}
|-
| <math>(a = b) <math>\Rightarrow</math> (ac = bc)</math> || aligh = "right" | {ν}
|{<math>\nu</math>}
|}
 
Как видно, первые три правила являются описанием свойств рефлексивности, симметричности и транзитивности. Набор этих свойств являет собой характеристики отношения эквивалентности, то есть отношение конвертируемости (<math>=</math>) делит всё множество комбинаторных
термов на некоторые классы эквивалентности, относительно которых можно сказать, что находящиеся в них термы конвертируемы друг в друга (эквивалентны друг другу).
рефлексивности, симметричности и транзитивности. Набор этих свойств
являет собой характеристики отношения эквивалентности, т.&nbsp;е.
отношение конвертируемости (<math>=</math>) делит всё множество комбинаторных
термов на некоторые классы эквивалентности, относительно которых
можно сказать, что находящиеся в них термы конвертируемы друг в
друга (эквивалентны друг другу).
 
Дополнительно надо отметить, что далее под именем комбинатора будет пониматься символ, его обозначающий, под сигнатурой комбинатора будет пониматься левая часть правила, а под характеристикой — правая часть правила, описывающего сам комбинатор.
пониматься символ, его обозначающий, под сигнатурой комбинатора
будет пониматься левая часть правила, а под характеристикой &mdash;
правая часть правила, описывающего сам комбинатор.
 
== Примеры сложных комбинаторов ==
 
Вполне естественно, что создатели комбинаторной логики не ограничились использованием двух базовых комбинаторов — <math>\mathbf S</math> и <math>\mathbf K</math>. Хотя они и составляют минимальный базис, но запись функций только через них увеличивает громоздкость определений с ростом сложности функций. Поэтому для упрощения записи определений более сложных комбинаторов и комбинаторных термов были разработаны дополнительные комбинаторы, из которых также можно составлять базисы.
Вполне естественно, что создатели комбинаторной логики не
ограничились использованием двух базовых комбинаторов &mdash;
'''S''' и '''K'''. Хотя они и составляют минимальный
базис, но запись функций только через них увеличивает громоздкость
определений с ростом сложности функций. Поэтому для упрощения записи
определений более сложных комбинаторов и комбинаторных термов были
разработаны дополнительные комбинаторы, из которых также можно
составлять базисы.
 
К таким комбинаторам относятся следующие:
 
# <math>\mathbf{ B}\, xyz = x(yz).</math>.
# <math>\mathbf{ C}\, xyz = xzy.</math>.
# <math>\mathbf{ W}\, xy = xyy</math>.
 
Данные комбинаторы весьма существенно сокращают некоторые преобразования.{{Ref|Curry}}
преобразования {{Ref|Karri}}
 
Ради этого многие комбинаторы даже получили свои собственные наименования. Так комбинатор <math>\mathbf I</math> называется «комбинатором тождества», комбинатор <math>\mathbf K</math> — «канцелятор», комбинатор <math>\mathbf S</math> — «коннектор», комбинатор <math>\mathbf B</math> — «композитор», комбинатор <math>\mathbf C</math> — «пермутатор» и комбинатор <math>\mathbf W</math> — «дубликатор».
Ради этого многие
комбинаторы даже получили свои собственные наименования. Так
комбинатор '''I''' называется «комбинатором тождества»,
комбинатор '''K''' &mdash; «канцелятор», комбинатор
'''S''' &mdash; «коннектор», комбинатор '''B''' &mdash;
«композитор», комбинатор '''C''' &mdash; «пермутатор» и
комбинатор '''W''' &mdash; «дубликатор».
 
Однако вполне понятно, что все перечисленные комбинаторы можно выразить друг через друга. Следующие формулы показывают выражение новых комбинаторов через уже известные:
выразить друг через друга. Следующие формулы показывают выражение
новых комбинаторов через уже известные:
 
<math> \mathbf{ B} \equiv \mathbf{ S} (\mathbf{K}\mathbf{SKS})\mathbf{ K}</math>
 
<math>\mathbf C \equiv \mathbf S \biggr( \Big(\mathbf S(\mathbf{KS})\mathbf K \Big) \Big(\mathbf S(\mathbf{KS})\mathbf K \Big) \mathbf S \biggr) (\mathbf{KK})</math>
 
<math> \mathbf{C} W \equiv \mathbf{SSS}(( \mathbf{S}Big( \mathbf{ K}\mathbf{S})\mathbf{K})(\mathbf{S}(\mathbf{K}\mathbf{SSKK}) \mathbf{K})\mathbf{S})(\mathbf{K}\mathbf{K}Big)</math>
 
Вдумчивому читателю предлагается самостоятельно проверить данные формулы. Для этого достаточно воспользоваться аксиомами для комбинаторов <math>\mathbf S</math> и <math>\mathbf K</math> и подставить в формулы переменные в заданном количестве (согласно определениям).
 
Однако возникает вопрос. На основании чего получены перечисленные выражения комбинаторов <math>\mathbf B</math>, <math>\mathbf C</math> и <math>\mathbf W</math> через базисные? Как создать такие выражения самостоятельно? Можно попытаться ответить на этот вопрос, самостоятельно найдя выражение комбинатора <math>\mathbf I</math>, как самого простого. Это можно проделать на основании следующих рассуждений.
<math> \mathbf{W} \equiv \mathbf{S}\mathbf{S}(\mathbf{K}(\mathbf{S}\mathbf{K}\mathbf{K}))</math>
 
Выражение комбинатора <math>\mathbf I</math> может начинаться либо с комбинатора <math>\mathbf S</math>, либо с комбинатора <math>\mathbf K</math>. При помощи цифр в следующих записях будут обозначаться недостающие объекты, которые ещё необходимо найти. В этом случае два возможных пути поиска выражения для комбинатора <math>\mathbf I</math> выглядят так:
 
# <math>\mathbf K\,1\,x\; \stackrel\mathbf K=\; 1 \neq x</math>;
# <math>\mathbf S\,1\,2\,x\; \stackrel\mathbf S=\; 1\,x\,(2\,x) = \dots</math>.
 
Здесь видно, что первая альтернатива не подходит автоматически, так как канцелятор <math>\mathbf K</math> отменяет переменную <math>x</math>, которая должна появиться в самом конце. Соответственно далее надо рассматривать только вторую альтернативу и искать способ выражения неизвестных объектов <math>1</math> и <math>2</math>. Они также могут быть либо
Вдумчивому читателю предлагается самостоятельно проверить данные
комбинатором <math>\mathbf S</math>, либо комбинатором <math>\mathbf K</math>. Соответственно, подставляя эти комбинаторы вместо неизвестного объекта <math>1</math>, можно получить:
формулы. Для этого достаточно воспользоваться аксиомами для
комбинаторов '''S''' и '''K''' и подставить в формулы
переменные в заданном количестве (согласно определениям).
 
# <math>\mathbf K\,x\,(2\,x)\; \stackrel\mathbf K=\; x</math>;
Однако возникает вопрос. На основании чего получены перечисленные
# <math>\mathbf S\,x\,(2\,x) =\, ?</math>.
выражения комбинаторов '''B''', '''C''' и
'''W''' через базисные? Как создать такие выражения
самостоятельно? Можно попытаться ответить на этот вопрос,
самостоятельно найдя выражение комбинатора '''I''', как
самого простого. Это можно проделать на основании следующих
рассуждений.
 
Как видно, первая альтернатива уже дала необходимый результат, а во второй альтернативе не хватает операндов у комбинатора <math>\mathbf S</math>. Поэтому вторую альтернативу можно не рассматривать, а вернуться только к первой. В ней остаётся неизвестный объект <math>2</math>, который не участвует в цепочке вывода, так как уничтожается канцелятором. Поэтому вместо него может стоять любой комбинатор, например, всё тот же <math>\mathbf K</math>. Так и получается, что выражение комбинатора тождества таково:
Выражение комбинатора '''I''' может начинаться либо с
комбинатора '''S''', либо с комбинатора '''K'''. При
помощи цифр в следующих записях будут обозначаться недостающие
объекты, которые ещё необходимо найти. В этом случае два возможных
пути поиска выражения для комбинатора '''I''' выглядят так:
 
<math>\mathbf I \equiv \mathbf{SKK}</math>
[[Изображение:K1x.jpg]]
 
Этот пример также показал, что способов разложения объектов в комбинаторном базисе существует бесконечное множество, поэтому всегда имеет смысл говорить о «минимальном» разложении, то есть таком, в записи которого используется минимальное число комбинаторов и скобок.
Здесь видно, что первая альтернатива не подходит автоматически,
т.&nbsp;к. канцелятор '''K''' отменяет переменную <math>x</math>, которая
должна появиться в самом конце. Соответственно далее надо
рассматривать только вторую альтернативу и искать способ выражения
неизвестных объектов <math>1</math> и <math>2</math>. Они также могут быть либо
комбинатором '''S''', либо комбинатором '''K'''.
Соответственно, подставляя эти комбинаторы вместо неизвестного
объекта <math>1</math>, можно получить:
 
Но описанный процесс не так прост, как может показаться на самом деле. Достаточно попробовать разложить подобным образом относительно простой комбинатор <math>\mathbf B</math>, чтобы понять, что в процессе такого рассмотрения альтернатив дерево решений растёт подобно снежному кому. Поэтому ради облегчения процесса выражения объектов с заданными комбинаторными характеристиками были созданы специальные правила. Данные правила относятся к выражению в базисе <math>\mathbf S</math>, <math>\mathbf K</math>, <math>\mathbf I</math>
[[Изображение:Kx2x.jpg]]
 
#<math>\mathbf T[v] \Rightarrow v</math>, где <math>v</math> — переменная.
Как видно, первая альтернатива уже дала необходимый результат, а
#<math>\mathbf T[(E_1E_2)] \Rightarrow (\mathbf T[E_1]\mathbf T[E_2])</math>.
во второй альтернативе не хватает операндов у комбинатора
#<math>\mathbf T[\lambda x.x] \Rightarrow \mathbf I</math>.
'''S'''. Поэтому вторую альтернативу можно не рассматривать,
#<math>\mathbf T[\lambda x.y] \Rightarrow \mathbf Ky</math>, если <math>y \ne x</math>.
а вернуться только к первой. В ней остаётся неизвестный объект <math>2</math>,
#<math>\mathbf T[\lambda x.\lambda y.E] \Rightarrow \mathbf T[\lambda x.\mathbf T[\lambda y.E]]</math>.
который не участвует в цепочке вывода, т.&nbsp;к. уничтожается
#<math>\mathbf T[\lambda x.(E_1E_2)] \Rightarrow \mathbf{ST}[\lambda x.E_1] \mathbf T[\lambda x.E_2]</math>
канцелятором. Поэтому вместо него может стоять любой комбинатор,
например, всё тот же '''K'''. Так и получается, что выражение
комбинатора тождества таково:
 
В этих правилах используется λ-нотация, которая принята в λ-исчислении. Привести комбинатор с его сигнатурой и характеристикой к λ-нотации довольно просто — надо вместо символа, обозначающего сам комбинатор, использовать символ «λ», а вместо символа «<math>=</math>» использовать точку «<math>.</math>».
<math> \mathbf{I} \equiv \mathbf{S} \mathbf{K} \mathbf{K}</math>
 
В следующем разделе приведены определения типов данных и функций на языке Haskell, которые осуществляют перевод заданного комбинатора в базис <math>\mathbf S</math>, <math>\mathbf K</math>, <math>\mathbf I</math>. Однако для закрепления материала читателю предлагается самостоятельно выразить в базисе <math>\mathbf S</math>, <math>\mathbf K</math>, <math>\mathbf I</math> следующие комбинаторы с такими характеристиками:
Этот пример также показал, что способов разложения объектов в
комбинаторном базисе существует бесконечное множество, поэтому
всегда имеет смысл говорить о «минимальном» разложении, т.&nbsp;е.
таком, в записи которого используется минимальное число комбинаторов
и скобок.
 
#<math>\mathbf \Psi\, abcd = a(bc)(bd)</math>
#<math>\mathbf{C^{[2]}}\,abcd = acdb</math>
#<math>\mathbf{C_{[2]}}\,abcd = adbc</math>
#<math>\mathbf{B^2}\,abcd = a(bcd)</math>
#<math>\mathbf{C^{[3]}}\,abcde = acdeb</math>
#<math>\mathbf{C_{[3]}}\,abcde = aebcd</math>
#<math>\mathbf{B^3}\,abcde = a(bcde)</math>
#<math>\mathbf \Phi\, abcd = a(bd)(cd)</math>
 
== Модуль на языке Haskell для преобразования комбинаторов ==
Но описанный процесс не так прост, как может показаться на самом
деле. Достаточно попробовать разложить подобным образом относительно
простой комбинатор '''B''', чтобы понять, что в процессе
такого рассмотрения альтернатив дерево решений растёт подобно
снежному кому. Поэтому ради облегчения процесса выражения объектов
с заданными комбинаторными характеристиками были созданы специальные
правила. Данные правила относятся к выражению в базисе '''S,K,I'''
 
В этом разделе приводится текст программы на [[w:Haskell|языке Haskell]], которая преобразует заданный комбинатор в базис <math>\mathbf S</math>, <math>\mathbf K</math>, <math>\mathbf I</math>. Для того, чтобы понимать приведённые определения, необходимо быть знакомым с [[w:Синтаксис (программирование)|синтаксисом]] этого языка на уровне, достаточном для определения [[w:Тип данных|типов]] и [[w:Функция (программирование)|функций]]. Рассмотрение этих тем выходит за рамки этой статьи, поэтому заинтересованного читателя можно отослать к специализированной литературе.
#<math>\mathbf{T}[v] \Rightarrow v</math>, где <math>v</math> &mdash; переменная.
#<math>\mathbf{T}[(E_{1}E_{2})] \Rightarrow (\mathbf{T}[E_{1}]\mathbf{T}[E_{2}])</math>.
#<math>\mathbf{T}[\lambda x.x] \Rightarrow \mathbf{I}</math>.
#<math>\mathbf{T}[\lambda x.y] \Rightarrow \mathbf{K}y</math>, если <math>y \ne x</math>.
#<math>\mathbf{T}[\lambda x.\lambda y.E] \Rightarrow \mathbf{T}[\lambda x.\mathbf{T}[\lambda y.E]]</math>.
#<math>\mathbf{T}[\lambda x.(E_{1}E_{2})] \Rightarrow \mathbf{S} \mathbf{T}[\lambda x.E_{1}] \mathbf{T}[\lambda x.E_{2}]</math>
 
Для преобразования комбинаторов необходимо для начала определить тип данных для их представления. В соответствии с определением комбинаторного терма определение такого типа выглядит так:
В этих правилах используется <math>\lambda</math>-нотация, которая
принята в <math>\lambda</math>-исчислении. Привести комбинатор с его
сигнатурой и характеристикой к <math>\lambda</math>-нотации довольно
просто &mdash; надо вместо символа, обозначающего сам комбинатор,
использовать символ (<math>\lambda</math>), а вместо символа (<math>=</math>) использовать
точку (<math>.</math>).
 
В следующем разделе приведены определения типов данных и функций на
языке Haskell, которые осуществляют перевод заданного комбинатора в
базис '''S,K,I'''. Однако для закрепления материала читателю
предлагается самостоятельно выразить в базисе '''S,K,I''' следующие
комбинаторы с такими характеристиками:
 
#<math>\mathbf{\Psi}abcd = a(bc)(bd)</math>
#<math>\mathbf{C^{[2]}}abcd = acdb</math>
#<math>\mathbf{C_{[2]}}abcd = adbc</math>
#<math>\mathbf{B^{2}}abcd = a(bcd)</math>
#<math>\mathbf{C^{[3]}}abcde = acdeb</math>
#<math>\mathbf{C_{[3]}}abcde = aebcd</math>
#<math>\mathbf{B^{3}}abcde = a(bcde)</math>
#<math>\mathbf{\Phi}abcd = a(bd)(cd)</math>
 
==Модуль на языке Haskell для преобразования комбинаторов==
 
В этом разделе приводится текст программы на языке Haskell, которая
преобразует заданный комбинатор в базис '''S,K,I'''. Для того, чтобы
понимать приведённые определения, необходимо быть знакомым с
синтаксисом этого языка на уровне, достаточном для определения типов
и функций. Рассмотрение этих тем выходит за рамки этой статьи,
поэтому заинтересованного читателя можно отослать к
специализированной литературе.
 
Для преобразования комбинаторов необходимо для начала определить тип
данных для их представления. В соответствии с определением
комбинаторного терма определение такого типа выглядит так:
 
<code>data Combinator = Var String
Строка 316 ⟶ 163 :
deriving Eq</code>
 
Это определение полностью соответствует математическому, которое гласит, что комбинаторный терм — это либо переменная (<code>Var</code> — от английского слова «variable»), либо абстракция (<code>Lam</code>} — от английского слова «lambda»), либо
приложение одного комбинаторного терма к другому (<code>App</code> — от английского слова «application»).
гласит, что комбинаторный терм &mdash; это либо переменная (<tt>Var</tt> &mdash;
от английского слова «variable»), либо абстракция
(<tt>Lam</tt>} &mdash; от английского слова «lambda»), либо
приложение одного комбинаторного терма к другому (<tt>App</tt> &mdash;
от английского слова «application»).
 
Для того, чтобы иметь возможность просматривать полученные
результаты преобразования комбинаторных термов, необходимо
определить тип <tt>Combinator</tt> экземпляром класса <tt>Show</tt>,
который является классом величин, которые могут быть отображены.
Конечно, интерпретатор языка Haskell может самостоятельно
определить такой экземпляр, но он сделает это не так красиво, как
можно сделать вручную. Поэтому вводится следующее определение:
 
Для того, чтобы иметь возможность просматривать полученные результаты преобразования комбинаторных термов, необходимо определить тип <code>Combinator</code> экземпляром [[w:Класс (программирование)|класса]] <code>Show</code>, который является классом величин, которые могут быть отображены. Конечно, [[w:Интерпретатор|интерпретатор]] языка Haskell может самостоятельно определить такой экземпляр, но он сделает это не так красиво, как можно сделать вручную. Поэтому вводится следующее определение:
 
<code>instance Show Combinator where
Строка 336 ⟶ 172 :
show (App x y) =
case y of
App _ _ ->&gt; showLam x ++ "(" ++ show y ++ ")"
_ ->&gt; showLam x ++ showLam y
where showLam l@(Lam _ _) = "(" ++ show l ++ ")"
showLam x = show x
show (Lam x e) = "\\" ++ x ++ "." ++ show e</code>
 
Здесь видно, что переменная отображается просто своим именем, которое представляется строкой символов. Применение комбинаторных термов друг к другу просто записывается перечислением комбинаторных термов друг за другом со взятием в скобки, если второй терм сложный. А абстракция записывается при помощи символа (<code>\</code>) с указанием сигнатуры и характеристики.
 
Базис <math>\mathbf S</math>, <math>\mathbf K</math>, <math>\mathbf I</math> определяется при помощи константных функций, возвращающих комбинаторные термы в виде переменных с известными именами: <code>i = Var "I"!, k = Var "K"!, s = Var "S"!</code>.
Здесь видно, что переменная отображается просто своим именем,
которое представляется строкой символов. Применение комбинаторных
термов друг к другу просто записывается перечислением комбинаторных
термов друг за другом со взятием в скобки, если второй терм сложный.
А абстракция записывается при помощи символа (<math>\backslash</math>) с
указанием сигнатуры и характеристики.
 
Дополнительно, хотя это и не обязательно, можно реализовать [[w:Предикат|предикат]], который проверяет, является ли заданная переменная свободной в исследуемом комбинаторном терме. Этот предикат определяется так:
Базис '''S,K,I''' определяется при помощи константных функций,
возвращающих комбинаторные термы в виде переменных с известными
именами: <tt>i = Var "I"!, k = Var "K"!, s = Var "S"!</tt>.
 
<code>free :: String -&gt; Combinator -&gt; Bool
 
Дополнительно, хотя это и не обязательно, можно реализовать
предикат, который проверяет, является ли заданная переменная
свободной в исследуемом комбинаторном терме. Этот предикат
определяется так:
 
<code>free :: String -> Combinator -> Bool
free x (Var y) = x == y
free x (App e1 e2) = free x e1 || free x e2
Строка 368 ⟶ 192 :
Всё в полном соответствии с математическим определением.
 
Наконец, сама функция <code>transform</code>, которая осуществляет перевод комбинаторного терма в базис <math>\mathbf S</math>, <math>\mathbf K</math>, <math>\mathbf I</math>. Её определение также выглядит в полном соответствии с перечисленными в предыдущем разделе правилами трансформации. Здесь можно видеть всю силу выразительности языка Haskell, которая позволяет записывать определения функций практически в математической нотации.
Наконец, сама функция <tt>transform</tt>, которая осуществляет
перевод комбинаторного терма в базис '''S,K,I'''. Её определение также
выглядит в полном соответствии с перечисленными в предыдущем разделе
правилами трансформации. Здесь можно видеть всю силу
выразительности языка Haskell, которая позволяет записывать
определения функций практически в математической нотации.
 
<code>transform :: Combinator ->&gt; Combinator
transform (Var x) = Var x
transform (App x y) = App (transform x)
Строка 386 ⟶ 205 :
(transform (Lam x e2))</code>
 
Видно, что определение этой функции полностью совпадает с описанием правил трансформации комбинаторных термов. Однако данная функция не позволяет получить минимальное выражение комбинаторного терма в базисе <math>\mathbf S</math>, <math>\mathbf K</math>, <math>\mathbf I</math>. Она возвращает один из возможных вариантов разложения терма. Например, комбинатор <math>\mathbf B</math>, закодированный при помощи λ-нотации следующим образом:
Видно, что определение этой функции полностью совпадает с описанием
правил трансформации комбинаторных термов. Однако данная функция
не позволяет получить минимальное выражение комбинаторного терма в
базисе '''S,K,I'''. Она возвращает один из возможных вариантов
разложения терма. Например, комбинатор '''B''',
закодированный при помощи <math>\lambda</math>-нотации следующим
образом:
 
<code>b = Lam "x"
Строка 401 ⟶ 214 :
(Var "z")))))</code>
 
Если передать это определение функции <ttcode>transform</ttcode>, то на выходе будет такая конструкция: <code>S(S(KS)(S(KK)(S(KS)(S(KK)I))))(K(S(S(KS)(S(KK)I))(\mathbf{KI})))</code>!
выходе будет такая конструкция: <tt> S(S(KS)(S(KK)(S(KS)(S(KK)I))))(K(S(S(KS)(S(KK)I))(KI)))</tt>!
 
== Представление данных и функций ==
 
Было бы странно, если бы комбинаторная логика не могла бы быть тем инструментом, при помощи которого можно было бы выражать различные объекты. Действительно, формализм комбинаторной логики, несмотря на весьма ограниченный алфавит, является вполне достаточным для выражения таких базовых понятий математики, как [[w:Булева алгебра|булевы]] значения истины, упорядоченные пары некоторых значений, [[w:Натуральное число|натуральные числа]], [[w:Список (информатика)|списки]]. Это, в свою очередь, позволяет практически полностью смоделировать теорию [[w:Функциональное программирование|функционального программирования]] в рамках простой комбинаторной логики.
Было бы странно, если бы комбинаторная логика не могла бы быть тем
инструментом, при помощи которого можно было бы выражать различные
объекты. Действительно, формализм комбинаторной логики, несмотря на
весьма ограниченный алфавит, является вполне достаточным для
выражения таких базовых понятий математики, как булевские значения
истины, упорядоченные пары некоторых значений, натуральные
числа, списки. Это, в свою очередь, позволяет практически
полностью смоделировать теорию функционального программирования в
рамках простой комбинаторной логики.
 
Сам по себе способ кодирования данных в рамках комбинаторной логики не является достаточно выразительным, более того, иной раз кажется, что такое кодирование вычурно и надумано. С точки зрения эффективности вычислений также имеются проблемы — оптимизация в прикладных [[w:Транслятор|трансляторах]] [[w:Язык программирования|языков программирования]] позволяет кодировать и проводить вычисления над закодированными данными более эффективно. Однако этот способ кодирования данных является довольно интересным с точки зрения математики, так как позволяет понять, в том числе, и то, что данные могут нести внутри себя и способы их обработки.
Сам по себе способ кодирования данных в рамках комбинаторной логики
не является достаточно выразительным, более того, иной раз кажется,
что такое кодирование вычурно и надумано. С точки зрения
эффективности вычислений также имеются проблемы &mdash; оптимизация в
прикладных трансляторах языков программирования позволяет кодировать
и проводить вычисления над закодированными данными более эффективно.
Однако этот способ кодирования данных является довольно интересным с
точки зрения математики, т.&nbsp;к. позволяет понять, в том числе, и то,
что данные могут нести внутри себя и способы их обработки.
 
===Булевские Булевы значения ===
 
Для кодирования булевых величин необходимо иметь способ представления в комбинаторной логике значений <math>\mathbf{true}</math>, <math>\mathbf{false}</math>, а также служебную структуру <math>\mathbf{if}</math>. Обычно для этих целей используются следующие правила кодирования:
Для кодирования булевских величин необходимо иметь способ
представления в комбинаторной логике значений '''true''',
'''false''', а также служебную структуру '''if'''.
Обычно для этих целей используются следующие правила кодирования:
 
#'''true''' <math>\mathbf{true} \equiv \mathbf K</math> '''K'''.
#'''false''' <math>\mathbf{false} \equiv \mathbf {KI}</math> '''KI'''.
#'''if''' <math>\mathbf{if} \equiv \mathbf I</math> '''I'''.
 
Действительно, предложенный способ кодирования можно легко проверить:
 
<math>\mathbf{if\ true}\ x\, y \equiv \mathbf I\, \mathbf K\, x\, y\; \stackrel\mathbf I=\; \mathbf K\, x\, y\; \stackrel\mathbf K=\; x</math>.
Действительно, предложенный способ кодирования можно легко
проверить:
 
<math>\mathbf{if\ false}\ x\, y \equiv \mathbf I\, \mathbf K\, \mathbf I\, x\, y\; \stackrel\mathbf I=\; \mathbf K\, \mathbf I\, x\, y\; \stackrel\mathbf K=\; \mathbf I\, y\; \stackrel\mathbf I=\; y</math>.
[[Изображение:iftrue.jpg]]
 
Как можно видеть, кодирование служебного слова <math>\mathbf{if}</math> вообще не является необходимым — можно вполне обойтись и без него. Сами по себе значения истинности являются условными выражениями, так как возвращают первый или второй операнд в зависимости от своей природы. Поэтому комбинатор <math>\mathbf{if}</math> является тождеством для трёх операндов, первый из которых должен быть значением истинности.
Как можно видеть, кодирование служебного слова '''if'''
вообще не является необходимым &mdash; можно вполне обойтись и без него.
Сами по себе значения истинности являются условными выражениями,
т.&nbsp;к. возвращают первый или второй операнд в зависимости от своей
природы. Поэтому комбинатор '''if''' является тождеством для
трёх операндов, первый из которых должен быть значением истинности.
 
Вполне естественно, что над представленными значениями истинности должны иметься функции для выполнения базовых операций булевой логики. Такие базовые операции могут быть выражены через условные выражения. Способы кодирования трёх базисных булевых операций (отрицание, конъюнкция и дизъюнкция) выглядят следующим образом:
должны иметься функции для выполнения базовых операций булевской
логики. Такие базовые операции могут быть выражены через условные
выражения. Способы кодирования трёх базисных булевских операций
(отрицание, конъюнкция и дизъюнкция) выглядят следующим образом:
 
#'''not''' <math>\mathbf{not} \equiv</math> '''\mathbf C (\mathbf{C\ if\ false})\ \mathbf{true'''}</math>.
#'''and''' <math>\mathbf{and} \equiv</math> '''\mathbf B (\mathbf{CC\ false})\ \mathbf{if}</math>.
#'''or''' <math>\mathbf{or} \equiv</math> '''\mathbf{C\ if\ true'''}</math>.
 
Читателю предлагается самостоятельно проверить данные тождества на предмет их верности. Для этого необходимо рассмотреть таблицы истинности для перечисленных логических операций и сравнить их с традиционными таблицами истинности.
предмет их верности. Для этого необходимо рассмотреть таблицы
истинности для перечисленных логических операций и сравнить их с
традиционными таблицами истинности.
 
=== Нумералы [[w:Чёрч, Алонзо|Чёрча]] ===
 
Вполне понятно, что для кодирования чисел или подобных им объектов можно использовать любой способ выражения, главное, что потом на таком способе можно было бы построить приемлемые операции, тождественные тем, что определены для чисел. Поэтому, собственно, способов кодирования чисел существует множество. Но самым первым способом был тот, что предложен А. Чёрчем, и теперь носит наименование «нумералы Чёрча».
Вполне понятно, что для кодирования чисел или подобных им объектов
можно использовать любой способ выражения, главное, что потом на
таком способе можно было бы построить приемлемые операции,
тождественные тем, что определены для чисел. Поэтому, собственно,
способов кодирования чисел существует множество. Но самым первым
способом был тот, что предложен А. Чёрчем, и теперь носит
наименование «нумералы Чёрча».
 
Нумералом Чёрча порядка <math>n</math> называется такой объект <math>\overline n</math> (<math>n</math> — натуральное число из расширенного множества натуральных чисел <math>\mathbb{N}^+</math>), который выражается через базовые комбинаторы следующим образом:
<math>\overline{n}</math> (<math>n</math> &mdash; натуральное число из расширенного
множества натуральных чисел <math>\mathbb{N}^{+}</math>), который выражается
через базовые комбинаторы следующим образом:
 
<math>\overline n = (\mathbf{SB})^n (\mathbf{KI})</math>,
[[Изображение:SB1.jpg]]
 
где под записью <math>(\mathbf{(SB})^{n}}</math> понимается <math>n</math>-кратное приложение объекта <math>(\mathbf{SB})</math> к самому себе:
<math>n</math>-кратное приложение объекта <math>\mathbf{(SB)}</math> к
самому себе:
 
<math>(\mathbf{SB})^{0}(\mathbf{KI}) = \mathbf{KI,}</math>,
 
<math>(\mathbf{SB})^{1}(\mathbf{KI}) = \mathbf{SB}(\mathbf{KI}),</math>,
 
<math>(\mathbf{SB})^{2}(\mathbf{KI}) = \mathbf{SB}(\mathbf{SB})(\mathbf{KI}),</math>,
 
<math>(\mathbf{SB})^{3}(\mathbf{KI}) = \mathbf{SB} \Big( \mathbf{SB}(\mathbf{SB}) \Big) (\mathbf{KI})</math>
 
и т.&nbsp;дтак далее. Т.&nbsp;е.То есть по индукции эти объекты можно определить как:
 
# <math>\overline 0 = (\mathbf{SB})^0(\mathbf{KI}) = \mathbf{KI}</math>.
# <math>\overline n = (\mathbf{SB})^n(\mathbf{KI}) = \mathbf{SB}(\mathbf{SB}{}^{n - 1})(\mathbf{KI})</math>, <math>n > 0</math>.
 
По своей сути эти комбинаторы создают итеративное применение заданной функции к некоторому аргументу, причём количество итераций равно определяемому нумералом числу:
#<math>\overline{0} = (SB)^{0}(KI) = KI</math>.
#<math>\overline{n} = (SB)^{n}(KI) = SB(SB^{n - 1})(KI)</math>, <math>n > 0</math>.
 
<math>\overline 0\, f x = x</math>
 
<math>\overline 1\, f x = f x</math>
По своей сути эти комбинаторы создают итеративное применение
заданной функции к некоторому аргументу, причём количество итераций
равно определяемому нумералом числу:
 
<math> \overline{0} n\, f x = \underbrace{f(f(\ldots(f}_n x)\ldots))</math>
 
Для этих объектов довольно простым способом можно определить функции для сложения, умножения и возведения в степень. Это делается следующим образом:
<math> \overline{1} f x = f x</math>
 
# <math> \overlinemathbf{nadd} f x =\equiv \underbracemathbf{f(fCI}(\ldots(f}_mathbf{nSB} x)\ldots))</math>.
# <math>\mathbf{mlt} \equiv \mathbf B</math>.
# <math>\mathbf{exp} \equiv \mathbf{CI}</math>.
 
Доказательство данных тождеств легко проводится по индукции и предлагается для самостоятельной проработки.
Для этих объектов довольно простым способом можно определить функции
для сложения, умножения и возведения в степень. Это делается
следующим образом:
 
=== Упорядоченные пары ===
#'''add''' <math>\equiv</math> '''CI(SB)'''.
#'''mlt''' <math>\equiv</math> '''B'''.
#'''exp''' <math>\equiv</math> '''CI'''.
 
Ещё один достаточно важный объект, имеющий большое практическое значение в функциональном программировании, является упорядоченная пара, состоящая из двух значений. Из пар создаются списки и списочные структуры, которые в свою очередь являются одним из основных объектов обработки в функциональных языках.{{Ref|LISP}}
Доказательство данных тождеств легко проводится по индукции и
предлагается для самостоятельной проработки.
 
Для кодирования пары при помощи комбинаторных термов необходимо создать функцию, которая является конструктором такой пары. Это можно сделать следующим образом:
===Упорядоченные пары===
 
<math>\mathbf{pair} \equiv \mathbf{BC}(\mathbf{CI})</math>.
Ещё один достаточно важный объект, имеющий большое практическое
значение в функциональном программировании, является упорядоченная
пара, состоящая из двух значений. Из пар создаются списки и
списочные структуры, которые в свою очередь являются одним из
основных объектов обработки в функциональных
языках {{Ref|LISP}}.
 
Данный комбинатор составляет пару из двух заданных объектов любой природы. Для того, чтобы достать эти объекты из пары, необходимы так называемые «селекторы», то есть функции для доступа к элементам пары. Эти селекторы можно определить так:
Для кодирования пары при помощи комбинаторных термов необходимо
создать функцию, которая является конструктором такой пары. Это
можно сделать следующим образом:
 
pair <math>\mathbf{head} \equiv \mathbf{CI\ true}</math> BC(CI),
 
<math>\mathbf{tail} \equiv \mathbf{CI\ false}</math>.
Данный комбинатор составляет пару из двух заданных объектов любой
природы. Для того, чтобы достать эти объекты из пары, необходимы
т.&nbsp;н. «селекторы», т.&nbsp;е. функции для доступа к элементам пары.
Эти селекторы можно определить так:
 
head <math>\equiv</math> CI true
tail <math>\equiv</math> CI false
Эти комбинаторы «вынимают» первое или второе значение из переданной им на вход пары. Например, можно доказать, что выражение:
переданной им на вход пары. Например, можно доказать, что
выражение:
 
head (pair <math>x</math> <math>y</math>) = <math>x</math>
 
<math>\mathbf{head} (\mathbf{pair}\, x\, y) = x</math>
для любого выражения <math>x</math>. Тоже самое можно сказать и о
селекторе '''tail'''. Читателю опять же рекомендуется
провести исследование этого выражения &mdash; это позволит закрепить
изученный материал и более тонко понять смысл и назначение
комбинаторной логики.
 
для любого выражения <math>x</math>. Тоже самое можно сказать и о селекторе <math>\mathbf{tail}</math>. Читателю опять же рекомендуется провести исследование этого выражения — это позволит закрепить изученный материал и более тонко понять смысл и назначение комбинаторной логики.
===Общие замечания===
 
=== Общие замечания ===
Надо отметить, что предложенные способы кодирования данных и методов
для их обработки при помощи инструментов комбинаторной логики
является скорее не заданной догмой, но шаблонами, по которым можно
производить вычисления над закодированными данными. Если рассмотреть
такие способы кодирования более подробно, то видно, что и нумералы
Чёрча, и упорядоченные пары могут принимать на вход не только сами
значения для кодирования, но и функции для их обработки.
 
Надо отметить, что предложенные способы кодирования данных и методов для их обработки при помощи инструментов комбинаторной логики является скорее не заданной догмой, но шаблонами, по которым можно производить вычисления над закодированными данными. Если рассмотреть такие способы кодирования более подробно, то видно, что и нумералы Чёрча, и упорядоченные пары могут принимать на вход не только сами значения для кодирования, но и функции для их обработки.
Так, определение пары является достаточно универсальным &mdash; оно не
ограничивает понятие упорядоченной пары какими-то специальными
рамками, а оставляет разработчику выбирать способ упаковки объектов
в пару. Поэтому любая пара в качестве функции ожидает на вход
некоторую функцию двух аргументов, которая после применения
возвращает к изначальным объектам и определяет саму пару. Это
значит, что и операции для распаковки пары (селекторы) должны быть
различными в каждом конкретном случае. Приведённые выше определения
являются шаблонами. Однако и эти шаблоны сами по себе также
работают.
 
Так, определение пары является достаточно универсальным — оно не ограничивает понятие упорядоченной пары какими-то специальными рамками, а оставляет разработчику выбирать способ упаковки объектов в пару. Поэтому любая пара в качестве функции ожидает на вход некоторую функцию двух аргументов, которая после применения возвращает к изначальным объектам и определяет саму пару. Это значит, что и операции для распаковки пары (селекторы) должны быть различными в каждом конкретном случае. Приведённые выше определения являются шаблонами. Однако и эти шаблоны сами по себе также работают.
Все эти рассуждения касаются и остальных примеров. Это значит, что комбинаторная логика
предоставляет учёным и разработчикам универсальный инструмент для
абстрактного проектирования методов для решения широкого класса
задач.
 
Все эти рассуждения касаются и остальных примеров. Это значит, что комбинаторная логика предоставляет учёным и разработчикам универсальный инструмент для абстрактного проектирования методов для решения широкого класса задач.
 
== Заключение ==
 
Рассмотренное в этой статье введение в основы комбинаторной логики не претендует на целостность изложения, да и невозможно в малой научно-популярной статье изложить сложную науку о вычислениях, на которой основана реализация многих функциональных языков программирования. Поэтому всех заинтересовавшихся читателей можно отослать к изучению комбинаторной логики и λ-исчисления по учебникам, полноценно описывающим эти интереснейшие направления логики. В качестве направлений для дальнейшего изучения можно посоветовать рассмотреть следующие вопросы:
Рассмотренное в этой статье введение в основы комбинаторной логики
не претендует на целостность изложения, да и невозможно в малой
научно-популярной статье изложить сложную науку о вычислениях, на
которой основана реализация многих функциональных языков
программирования. Поэтому всех заинтересовавшихся читателей можно
отослать к изучению комбинаторной логики и
<math>\lambda</math>-исчисления по учебникам, полноценно описывающим эти
интереснейшие направления логики. В качестве направлений для
дальнейшего изучения можно посоветовать рассмотреть следующие
вопросы:
 
# Синтез нового объекта с заданными комбинаторными характеристиками.
# Использование [[w:Редукция|редукции]] комбинаторов при помощи [[w:Граф (математика)|графов]], что позволяет проводить [[w:Ленивые вычисления|ленивые вычисления]], в том числе и потенциально бесконечных структур данных.
# Преобразование <math>n</math>-местных операторных функций в каррированные, позволяющие производить частичные вычисления.
# Типизация комбинаторов, которая позволяет разбить всё множество комбинаторов на некие классы эквивалентности по их типам (сортам).
# Оболочка Каруби — специальная категория в рамках комбинаторной логики, при помощи которой кодируются все объекты операторных вычислений, включая их типы.
# Выражение при помощи комбинаторов различных систем программирования, в том числе выражение языков [[w:Лисп|Лисп]], Haskell и прочих.
# Изучение суперкомбинаторов — объектов для ленивого вычисления значений некоторых выражений.
# Оптимизация вычислений путём комбинирования параметров — шаг к построению систем суперкомпиляции.
# Техники проведения синтаксического анализа на функциональных языках программирования.
 
Автор оригинального текста статьи благодарит Антонюка Д. А., который помог написать функции на языке Haskell для трансформации комбинаторных термов в базис <math>\mathbf S</math>, <math>\mathbf K</math>, <math>\mathbf I</math>
#Синтез нового объекта с заданными комбинаторными характеристиками.
#Использование редукции комбинаторов при помощи графов, что позволяет проводить ленивые вычисления, в том числе и потенциально бесконечных структур данных.
#Преобразование <math>n</math>-местных операторных функций в каррированные,позволяющие производить частичные вычисления.
#Типизация комбинаторов, которая позволяет разбить всё множество комбинаторов на некие классы эквивалентности по их типам (сортам).
#Оболочка Каруби &mdash; специальная категория в рамках комбинаторной логики, при помощи которой кодируются все объекты операторных вычислений, включая их типы.
#Выражение при помощи комбинаторов различных систем программирования,в том числе выражение языков Lisp, Haskell и прочих.
#Изучение суперкомбинаторов &mdash; объектов для ленивого вычисления значений некоторых выражений.
#Оптимизация вычислений путём комбинирования параметров &mdash; шаг к построению систем суперкомпиляции.
#Техники проведения синтаксического анализа на функциональных языках программирования.
 
== Примечания ==
Автор оригинального текста статьи благодарит Антонюка Д. А., который помог написать функции на языке Haskell для трансформации комбинаторных термов в базис '''S,K,I'''
 
# {{Note|lambda}} λ-исчисление — это наука о вычислениях, первоначально разработанная Алонзо Чёрчем для разрешения [[w:Парадокс Рассела|парадокса Б. Рассела о множестве всех множеств, не включающих самих себя в качестве подмножества]]. Рассмотрение этого направления логики выходит за рамки настоящей статьи.
==Примечания==
# {{Note|Curry}} Кстати, первоначально Х. Карри ввёл в своей работе именно комбинаторы <math>\mathbf B</math> и <math>\mathbf C</math>. В дальнейшем первоначальный базис был упрощён.
#{{Note|lambda}}<math>\lambda</math>-исчисление&mdash;это наука о вычислениях, первоначально разработанная Алонзо Чёрчем для разрешения парадокса Б.Рассела о множестве всех множеств, не включающих самих себя в качестве подмножества. Рассмотрение этого направления логики выходит за рамки настоящей статьи.
# {{Note|LISP}} Например, первый функциональный язык Лисп (LISP) назван так из-за своего назначения — «'''LIS'''t '''P'''rocessing» — «обработчик списков».
#{{Note|Karry}} Кстати, первоначально Х. Карри ввёл в своей работе именно комбинаторы '''B''' и '''C'''. В дальнейшем первоначальный базис был упрощён.
#{{Note|LISP}}Например, первый функциональный язык LISP назван так из-за своего назначения &mdash; «'''LIS'''t '''P'''rocessing» &mdash; «обработка списков».
 
[[Категория:Журнал_Журнал «Потенциал»]][[Категория:комбинаторная логика]][[Категория:математика в журнале_журнале «Потенциал»]]