https://gist.github.com/4139831

Вместо того, чтобы писать функцию, которая строит дерево, напишите функцию, генерирующую код, который строит это дерево. Более точно, определите функцию gen() так, чтобы она печатала код на Си в stdout и программа на выходе кодогенератора создавала то же самое дерево, что пришло в аргументе функции. Ниже некоторые детали:

alexo@euromake:/tmp$ git clone git://gist.github.com/4139831.git gentree
Cloning into gentree...
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 8 (delta 1), reused 5 (delta 1)
Receiving objects: 100% (8/8), done.
Resolving deltas: 100% (1/1), done.
alexo@euromake:/tmp$ cd gentree/
alexo@euromake:/tmp/gentree$ make
cc     gentree.c   -o gentree
./gentree 0 >output.c
make output
make[1]: Entering directory `/tmp/gentree'
cc     output.c   -o output
make[1]: Leaving directory `/tmp/gentree'
[ 0 = $(./output) ]
alexo@euromake:/tmp/gentree$ git grep Grammar
gentree.c:/* Grammar: <tree> ::= '0' | '1' <tree> <tree>. */
alexo@euromake:/tmp/gentree$ make TEST=1101000
./gentree 1101000 >output.c
make output
make[1]: Entering directory `/tmp/gentree'
cc     output.c   -o output
make[1]: Leaving directory `/tmp/gentree'
[ 1101000 = $(./output) ]
make: *** [all] Error 1
alexo@euromake:/tmp/gentree$ git grep TODO
gentree.c:      /* TODO: print some code in stdout. */
alexo@euromake:/tmp/gentree$ vi gentree.c
This is how you convert C source code (or any other ASCII text) into strings in C using Shell.

make(1) rules:

all: verbatim.h

verbatim.h: txt2cs.sed def.h sim.c
	printf '#define %s \\\n%s\n\n' >$*.tmp \
		INDEF "$$(sed -f txt2cs.sed def.h)"
	printf '#define %s \\\n%s\n' >>$*.tmp \
		INSIM "$$(sed -f txt2cs.sed sim.c)"
	mv $*.tmp $@

clean:
	-rm -fr verbatim.h *.tmp

sed(1) script:

s/\\/\\\\/g
s/"/\\"/g
s/	/\\t/g

$!s/^\(.*\)$/	"\1\\n" \\/
$s/^\(.*\)$/	"\1\\n"/

Output )
Приняты следующие дизайнерские решения относительно автоматического генератора симуляторов систем взаимодействия (см. "Анонс нового языка программирования"). Некоторые детали проектной документации подлежат уточнению позднее.

Определения

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

typedef struct {
  void *type;
  int index;
  void *aux[INAUXLEN];
} inagent;

extern const struct insign {
  void *offline;
  void *wire;
  void *type1;
  void *type2;
  ...
} insign;


Проект

1. Компилятор генерирует симулятор на языке ISO/IEC 9899:1999 за конечное время. Симулятор имеет один общий стек для всех активных пар. Симулятор предоставляет интерфейс приложению для проталкивания в вершину стека: void inpush(inagent *left, inagent *right). Только сам симулятор выталкивает вершину стека. Симулятор предоставляет интерфейс к запуску взаимодействия: void interact(void). Возврат из функции interact() происходит по достижении дна стека активных пар.

2. Симулятор вызывает внешнюю функцию inagent *inaux(void *aux, void *offline), определяемую приложением, чтобы получить ячейку, связанную своим главным портом с дополнительным портом aux. Значение аргумента берется только из массива aux в структуре inagent одного из агентов активной пары только на вершине стека. Симулятор не предполагает какой-либо структуры по адресу aux, никогда не разыменовывает его и использует аргумент функции inaux() исключительно в качестве идентификатора. Приложение полностью решает само, какой характер носит значение aux. Симулятор никогда не сохраняет возвращаемое значение функции и только копирует данные из памяти по этому адресу.

3. Сигнатура insign содержит поля offline, wire, type1, type2..., где type1, type2... - различные имена, участвующие в описании системы взаимодействия в виде \type1, \type2... Всем полям структуры insign присвоены различные целые значения. Если в описании системы взаимодействия участвует имя \offline, \wire или \special, где special - ключевое или зарезервированное слово ISO/IEC 9899:1999, результат компиляции неопределен.

4. Приложение определяет каждую связь между двумя дополнительными портами с порядковыми номерами a и b произвольных inagent alpha и inagent beta, соответственно, такой парой структур inagent left и inagent right, что insign.wire == left.type, insign.wire == right.type, left == right.aux[0], right == left.aux[0], left == alpha.aux[a] и right == beta.aux[b]. Если wire1 и wire2 - идентификаторы этих двух структур, то после вызова inaux(wire1, offline) симулятор ожидает, что последующий вызов inaux(wire2, unused) вернет указатель на такую структуру inagent agent, что agent.type == insign.offline и agent.aux[0] == offline. Если в описании одного правила имя соединения между двумя дополнительными портами используется один или более двух раз, результат компиляции неопределен.

5. Реализация компилятора может, но не обязана предоставлять опцию многопоточной обработки стека активных пар. В случае поддержки данной опции, реализация может затребовать дополнительные ограченения к приложению и побочным действиям правил взаимодействия.

Обоснование )

Интерфейс к симуляторам систем взаимодействия выбран по аналогии с теми в IEEE 1003.1-2008, что между утилитой yacc и приложениями, в том числе генерируемыми с помощью утилиты lex (см. "Interface to the Lexical Analyzer").
Чтобы упростить разработку симулятора нашей системы слепой перезаписи графов, мы подготовили проект нового языка программирования на основе нотации Lafont с описанием побочных действий на языке Си. По аналогии с yacc(1) и lex(1) выходными данными нашего компилятора будет модуль на языке Си. Синтаксис нашего языка программирования выбран близким к тому, как записываются правила взаимодействия в LaTeX.

    1 text: '$' CODE '$' rest

    2 rest: rule ';' rest
    3     | rule '.'

    4 rule: side CODE side

    5 side: cell
    6     | cell '[' list ']'

    7 tree: leaf
    8     | cell '(' list ')'

    9 list: tree
   10     | tree ',' list

   11 leaf: cell
   12     | NAME

   13 cell: '\\' NAME
   14     | '\\' NAME '_' CODE

Ниже пример программы на этом языке. Как видно по данному "Hello World", программы похожи по структуре к описанию парсеров и лексических анализаторов на yacc(1) и lex(1), с помощью которых и будет реализован компилятор нашего языка.

${
/* An example interaction system. */

#include <stdio.h>
}$

\fan_{i}[x, y] {
	printf("fan_%d >< fan_%d\n", i, j);
} \fan_{i}[x, y];

\fan_{i}[\fan_{i + j}(a, b), \fan_{i + j}(c, d)] {
	IFF(i != j);
	printf("fan_%d >< fan_%d\n", i, j);
} \fan_{j}[\fan_{i + j}(a, c), \fan_{i + j}(b, d)];

\erase {
	printf("erase >< fan_%d\n", j);
} \fan_{j}[\erase, \erase];

\erase {
	printf("erase >< erase\n");
} \erase.

https://github.com/codedot/inet
Ранее мы обозначили проблему декодирования результатов работы нашей системы (см. "Компиляция λ-выражений"). Это не новая проблема: "readback" известен своей сложностью в рамках темы оптимальной редукции, и едва ли не треть монографии на данной теме уделена "readback". Чтобы продолжить разработку нашего симулятора, нам потребуется разумное решение, которое бы подходило для нашей слепой стековой машины.

Напомним, что ранее мы ограничили множество λ-термов до λI-исчисления, чтобы упростить их компиляцию. Взамен мы получили право забыть об агентах ε, при этом не пожертвовав выразительными возможностями языка с точки зрения частичных рекурсивных функций. Теперь же мы дополнительно затребуем от вычисляемых выражений отсутствие свободных переменных. Это немного упростит "readback", избавив нас от рассмотрения особых случаев.

Итак, мы предполагаем некоторый λΙ-комбинатор. Головная нормальная форма λI-комбинатора всегда имеет вид λx1.…λxn.xi M1 … Mm, где m ≥ 0, n > 0, 0 < i < n. С точки зрения представлений в виде графов, подобных оптимальной редукции, - в том числе и в нашей системе слепой перезаписи - это, в частности, означает, что при условии наличия головной нормальной формы (в противном случае результат нас не интересует из-за бессмысленности выражения) становится возможным "readback" в виде следующей системы взаимодействия с побочными действиями:

Σ = {(ε, 0), (γ, 2), (ψ, 2), (c, 1), (@l, 2), (@r, 2)} ∪ {(xi, 0) | i ∈ N} ∪ {(λi, 1) | i ∈ N};

λii(ε)] >< xj + "xj";
λi[a] >< γ[λi + 1(c(a)), xi] + "(λxi.";
xi >< ψ[xi, xi];
xi >< γ[a, @l(xi, a)];
λ[a] >< @l[λ(@r(b, a)), b] + "(";
λ[a] >< c[λ(a)] + ")";
λ[ε] >< @r[λ(c(a)), a] + " ".

Нетрудно проверить, что такое "readback"-взаимодействие не зависит от симуляции основной системы. Таким образом, выполнять "readback" можно даже по мере редукции, не дожидаясь ее завершения.
Это музыкой навеяло:

alexo@euromake:/tmp/and$ cat and.c
void *
true_(x, y)
void *x, *y;
{
        return x;
}

void *
false_(x, y)
void *x, *y;
{
        return y;
}

void *
bool_[] = {false_, true_};

void *
and(x, y)
void *(*x)(), *y;
{
        return x(y, x);
}

main(argc, argv)
char *argv[];
{
        int x = argv[1][0] - '0';
        int y = argv[2][0] - '0';

        return (true_ == and(bool_[x], bool_[y]));
}
alexo@euromake:/tmp/and$ cat Makefile
all: and
        ./and 0 0; echo $$?
        ./and 0 1; echo $$?
        ./and 1 0; echo $$?
        ./and 1 1; echo $$?

clean:
        -rm -f and
alexo@euromake:/tmp/and$ make
cc     and.c   -o and
./and 0 0; echo $?
0
./and 0 1; echo $?
0
./and 1 0; echo $?
0
./and 1 1; echo $?
1
alexo@euromake:/tmp/and$ 
Едва заметным прошел момент, когда в нашем распоряжении оказалось достаточно материала, чтобы более явно показать, что системы слепой перезаписи графов действительно обладают полнотой по Тьюрингу. Как и предполагалось ранее, достаточно элегантным способом является симуляция направленных комбинаторов взаимодействия, которые сами обладают Тьюринг-полнотой (см. статью Lafont "Interaction Combinators" 1997 года). И хотя по общим соображениям этот факт был понятен еще полгода назад (см. "Логические операции без сравнений"), на данный момент доказательство можно построить из нескольких пунктов.

Мы будем опираться на предыдущие описания наших конструкций. Напомним, что первым шагом был выбор представления направленных комбинаторов γ, γ*, δ и δ*, а также двух видов связей между агентами: между двумя главными портами и между дополнительным и главным (см. "Слепые комбинаторы взаимодействия"). Затем мы получили представление для недостающего третьего вида связей, то есть между двумя дополнительными портами (см. "Слепые двунаправленные соединения"). Наконец, мы добились того, чтобы за один цикл работы системы количество используемых ячеек оставалось постоянным (см. "Баланс освобождаемой и выделяемой памяти"). В заключение мы пояснили выбор алгоритмов работы системы (см. "Трюки в синтаксическом сахаре λ-исчисления").

Итак, во-первых, заметим, что участие ε не влияет на ход вычислений. Поэтому мы можем заменить ε и ε* на свободные порты, которые, в свою очередь, симулируем парами ξ и ξ*, не связанными с чем-либо на противоположной стороне.

Во-вторых, дополним списки A, D, L и R неограниченным количеством фиктивных активных пар. (На практике это реализуемо через большое число процессов, в среднем дающих баланс выделяемой и освобождаемой памяти.)

В-третьих, по аналогии с aord построим алгоритм слепого копирования агентов, такой, что для данных α, β из набора {γ, δ} на месте β оказывается тот же тип агента, что и у агента α (пусть данная задача послужит несложным упражнением читателю). Копирование агентов γ* и δ* тривиально. Поясним, что копирование необходимо при дублировании (элемент списка D), для чего требуется преобразовать оба освобождаемых после аннигиляции агента (элемент списка A) неизвестных типов, в общем случае, в неизвестные типы.

Тогда в порядке обработки списков, диктуемом балансом освобождаемой и выделямой памяти, то есть за цикл по паре элементов из списков L и R и по одному элементу из списков A и D, машина слепой перезаписи симулирует взаимодействие направленных комбинаторов.



P. S. Как правильно заметил [livejournal.com profile] nivanych, полученная нами система имеет прямое отношение к конкатенационным языкам программирования. А именно, о списках A, D, L и R можно думать как о четырех стеках. Как мы видим, симуляция направленных комбинаторов взаимодействия с помощью слепой перезаписи графов в данном случае действительно породила стековую машину, имеющую одну кучу и четыре стека.
Только что понял, что именно мне напоминает схема вычисления с четырьмя списками L, A, D, R и алгоритмом сортировки "мусора" aord. Она во многом похожа на механизм транскрипции в биологии (процесс синтеза РНК с использованием ДНК в качестве матрицы).

В связи с этим становится яснее, почему системы взаимодействия часто связывают с формальной биологией и взаимодействием белков. В частности, Maribel Fernandez, автор и соавтор чуть менее, чем всех статей по системам взаимодействия, последние годы говорит о связи данной темы с молекулярной биологией, а также о системах перезаписи портов, при которой меняются связи, но не ноды. Последнее, в свою очередь, также близко к нашим конструкциям, в которых не используется никакой аллокатор памяти, а лишь производится перестановка указателей.

Произведя нехитрый поиск, я немедленно натолкнулся на книгу Maribel Fernandez под названием "Models of Computation: An Introduction to Computability Theory" и теперь жду не дождусь заполучить ее в руки:



http://www.amazon.co.uk/dp/1848824335

P. S. Получил, наконец-то. Оказалось неплохим вводным учебником по CS в его современном виде.
Ключевые слова "blind computation", возникшие в рамках нашей небольшой задачи, приводят к целой туче исследований по BQC, "blind quantum computation", в различных журналах и на arXiv, а также к похожим друг на друга новостным статьям, прошедшим лавиной по интернетам в начале текущего года.

В частности, BBC рассказывают о том, что слепые вычисления могут оказаться полезными в облаке, дабы обезопасить от проблемы Большого Брата:

http://www.bbc.co.uk/news/science-environment-16636580

Базворды те же: "can be carried out without a cloud computer ever knowing what the data is". Таким образом это тем более любопытно, так как одним из применений систем слепой перезаписи графов мы ранее рассматривали именно Web с точки зрения особенного устройства кэша предвычисленных в облаке результатов для дерева возможных действия пользователя на определенную глубину. И хотя подходы, вроде бы, разные: один по сути нацелен на облегчение клиента, а другой - на вычисления без дешифрования, - темы все-таки кажутся взаимосвязанными.

В связи с этим хотелось бы задать вопрос залу: кто что слышал про BQC, в каком оно примерно состоянии и насколько это действительно может иметь отношение к нашей теме? Сами мы не местные и квантовую физику не знаем.
Помимо материала, компактно собранного в шпаргалках по теории и практике λ-исчисления, ниже будут использоваться следующие обозначения. Во-первых, металамбда-абстракция λx.f(x) — безымянная запись теоретико-множественной функции f, например (λx.x2 + 1)(3) = 10. Во-вторых, определим множество кодов конечных последовательностей (при какой-либо стандартной их кодировке натуральными числами)

Seq = {<n1,…, nk> | k ∈ N, n1,…, nk ∈ N} ∪ {< >};
lh(< >) = 0;
α = <n1,…, nk> ∈ Seq ⇒ lh(α) = k;
α = <m1,…, mp>, β = <n1,…, nq> ∈ Seq ⇒ a * b = <m1,…, mp, n1,…, nq>;
α = <m1,…, mp>, β = <n1,…, nq> ∈ Seq ∧ p ≤ q ∧ m1 = n1 ∧ … ∧ mp = np ⇒ α ≤ β.

Пусть D = (D, ⊑) — частично упорядоченное множество с рефлексивным отношением ⊑. Тогда подмножество X ⊆ D называется направленным, если

X ≠ ∅ ∧ ∀x, y ∈ X: ∃z ∈ X: x ⊑ z ∧ y ⊑ z.

При этом D называется полным, если для любого направленного подмножества X ⊆ D существует супремум ⊔X ∈ D и имеется дно ⊥:

∃⊥ ∈ D: ∀x ∈ D: ⊥ ⊑ x.

Топология Скотта на полном частично упорядоченном множестве (D, ⊑) определяется следующим образом: множество O ⊆ D считается открытым, если

1) x ∈ O ∧ x ⊑ y ⇒ y ∈ O;
2) X ⊆ D ∧ ⊔X ∈ O ⇒ X ∩ O ≠ ∅.

Частичное отображение φ: X ↝ Y — это отображение φ, такое, что область определения Dom(φ) ⊆ X. Для x ∈ X запись φ(x)↓ означает, что φ(x) определено, то есть x ∈ Dom(φ); φ(x)↑ означает, что φ(x) не определено, то есть x ∉ Dom(φ).

Если Σ — некоторое множество символов, то частично Σ-помеченное дерево — это частичное отображение φ: Seq ↝ Σ × N, такое, что

1) φ(σ)↓ ∧ τ ≤ σ ⇒ φ(τ)↓;
2) φ(σ) = <a, n> ⇒ ∀k ≥ n: φ(σ * <k>)↑.

Обнаженное дерево, лежащее в основе частично Σ-помеченного дерева φ, — это дерево

Tφ = {< >} ∪ {σ | σ = σ' * <k> ∧ φ(σ') = <a, n> ∧ k < n}.

Если σ ∈ Tφ и φ(σ) = <a, n>, то a называется меткой в узле σ. Если же для σ ∈ Tφ φ(σ)↑, то говорят, что узел σ непомеченный. Частично помеченные деревья будем обозначать заглавными буквами и будем писать σ ∈ A вместо σ ∈ TA и A(α) = ⊥, когда A(α)↑, но все же α ∈ A.

Если Σ = {λx1.…λxn.x | n ≥ 0, x1,…, xn, x ∈ Λ}, то частично Σ-помеченное дерево называется деревом бемовского типа. Множество всех таких деревьем обозначим B. Поддерево дерева A, исходящее из узла α — это Aα = λβ.A(α * β). Очевидно, что ∀A ∈ B: ∀α: Aα ∈ B.

Комбинатор M разрешим, если

∃n: ∃N1,…, Nn ∈ Λ0: M N1 … Nn = I.

Например, комбинатор неподвижной точки разрешим, так как Y (K I) = K I (Y (K I)) = I. С другой стороны, Ω неразрешим. Произвольное λ-выражение разрешимо, если разрешим комбинатор λx1.…λxn.M, где {x1,…, xn} = FV(M).

λ-выражение M является головной нормальной формой, если оно имеет вид

M ≣ λx1.…λxn.x M1 … Mm, m, n ≥ 0.

Говорят, что M имеет головную нормальную форму N, если M = N. Главной называется та головная нормальная форма выражения, которая первой достигается его левой редукцией.

Уодсворт ввел класс λ-выражений, не имеющих головной нормальной формы, и привел доводы в пользу того, что элементы этого класса должны рассматриваться как бессмысленные выражения в λ-исчислении. Также ему принадлежит следующий важный результат: λ-выражение разрешимо тогда и только тогда, когда оно имеет головную нормальную форму. Таким образом, из неразрешимости M следует, что для любых выражений N1,…, Nn выражение M N1 … Nn не имеет нормальной формы.

Дерево Бема для терма M, обозначаемое через BT(M), — это дерево бемовского типа, определяемое следующим образом:

1) если M неразрешим, то ∀σ: BT(Μ)(σ)↑,
2) если M разрешим и имеет главную головную нормальную форму λx1.…λxn.x M0 … Mm - 1, то

BT(M)(< >) = <λx1.…λxn.x, m>;
k < m ⇒ BT(M)(<k> * σ) = BT(Mk)(σ);
k ≥ m ⇒ BT(M)(<k> * σ)↑.

Рассмотрим полное частично упорядоченное множество B = (B, ⊆) с топологией Скотта. Топология деревьев на множестве Λ — это наименьшая топология, в которой непрерывно отображение BT: Λ → B. Иными словами, открытые подмножества Λ имеют вид BT-1(O), где O открыто в топологии Скотта на B.

Используя топологию деревьев, можно выразить обычные понятия, относящиеся к λ-исчислению, в топологических терминах. Например, нормальные формы оказываются изолированными точками, а неразрешимые выражения — точками компактификации, то есть такими точками, единственной окрестностью которых является само топологическое пространство.

Доказано, что аппликация и абстракция непрерывны в топологии деревьев на Λ, причем для аппликации это нетривиальный результат, имеющий интересные следствия. Например, множество Sol ⊆ Λ разрешимых термов открыто. Действительно, в любом полном частично упорядоченном множестве множество {x | x ≠ ⊥} открыто по Скотту. Следовательно, множество Sol = BT-1{A | A ≠ ⊥} открыто в Λ.
В копилку цитат из монографии (Х. Барендрегт, «Ламбда-исчисление. Его синтаксис и семантика», перевод с английского Г. Е. Минца под редакцией А. С. Кузичева, Москва, «Мир», 1985), то есть туда же, где «и все в порядке»:

Комбинаторная алгебра — это аппликативная структура [множество с бинарной операцией]… с двумя выделенными элементами k, s, удовлетворяющими равенствам

k x y = x, s x y z = x z (y z).

Отметим, что комбинаторная алгебра нетривиальна [множество содержит больше одного элемента] тогда и только тогда, когда k ≠ s… При рассмотрении комбинаторных алгебр мы обычно молчаливо подразумеваем, что они нетривиальны. [Тривиальные комбинаторные алгебры соответствуют противоречивым эквациональным теориям.]

Аксиомы комбинаторных алгебр порождены не алгебраическими соображениями, а анализом рекурсивных процессов. Следующее утверждение показывает, что эти структуры — патологические с алгебраической точки зрения...

Нетривиальные комбинаторные алгебры

1) некоммутативны,
2) неассоциативны,
3) неконечны,
4) нерекурсивны.
Читая о моделях λ-исчисления в классической монографии по λ-исчислению (Х. Барендрегт, «Ламбда-исчисление. Его синтаксис и семантика», перевод с английского Г. Е. Минца под редакцией А. С. Кузичева, Москва, «Мир», 1985), я вдруг нашел ответ на свое старое недоумение, почему категорщикам не нравится отсутствие типов:

Используя категорное определение модели λ-исчисления, Скотт сделал следующие философские замечания.

1. Модели бестипового λ-исчисления возникают из декартово-замкнутых категорий с рефлексивным объектом. Сами декартово-замкнутые категории соответствуют типовому λ-исчислению… Поэтому типовое λ-исчисление первично, а бестиповая теория вторична.

2. Пусть C — декартово-замкнутая категория с рефлексивным объектом U. По лемме Йонеды категорию C можно вложить в топос D = SetCop. Используя семантику Крипке–Жуаяля, мы видим, что в D объект UU является полным пространством функций на U и потому U удовлетворяет аксиоме слабой экстенсиональности [∀x (M = N) → λx.M = λx.N] в D. За что приходится платить переходом к интуиционистской логике, так как классическая логика неполна относительно интерпретации Крипке–Жуаяля.

Некоторые комментарии. Что касается замечания 1, то имеются, конечно, красивые результаты о типовом λ-исчислении… Мы, однако, не согласны с выводом Скотта о первичности типового λ-исчисления по сравнению с бестиповой теорией. Во всяком случае это не верно с точки зрения вычислимости: типовое λ-исчисление (даже в присутствии рекурсора) способно представить лишь собственное подмножество множества рекурсивных функций, в то время как бестиповая теория представляет их все. В связи с замечанием 2 очень интересно предложение Скотта осуществить старую мечту Черча и Карри — изоморфизм UU ≃ U — внутри топоса…
Шпаргалка по нужной для практики теории готова, поэтому теперь попробуем сделать выжимку из практической части монографии Барендрегта по λ-исчислению. Речь пойдет о комбинаторной логике, теореме о неподвижной точке и синтаксическом сахаре.

Множество комбинаторов Ξ порождает наименьшее множество Ξ+ как замыкание по аппликации:

Ξ ⊆ Ξ+;
M, N ∈ Ξ+ ⇒ Μ Ν ∈ Ξ+.

Множество Ξ называется базисом, если ∀M ∈ Λ0: ∃N ∈ Ξ+: M = N.

Произвольную абстракцию можно смоделировать с помощью S и K:

S ≣ λx.λy.λz.x z (y z);
K ≣ λx.λy.x;
I ≣ λx.x = S K K;
x ∉ FV(P) ⇒ λx.P = K P;
λx.P Q = S (λx.P) (λx.Q).

Следовательно, комбинаторы K и S задают базис. Произвольный комбинатор M зачастую описывают не в виде λ-выражения, а с помощью аксиом. Например, формальная система комбинаторной логики CL определяется двумя аксиомами:

K P Q = P;
S P Q R = P R (Q R).

Существуют и одноточечные базисы: один из таких базисов задает комбинатор

X ≣ λx.x K S K.

Действительно, легко проверить, что X X X = K и X (X X) = S.

Стандартными комбинаторами считаются не только составляющие некоторый базис для комбинаторной логики, но и многие другие полезные λ-выражения. Одним из первых примеров обычно дают простейший комбинатор, не имеющий нормальной формы:

Ω ≣ ω ω, где ω ≣ λx.x x.

Далее, истинностные значения T ≣ K и F ≣ λx.I позволяют обозначить выражением B M N операцию «если B, то M, иначе N». Действительно: если B = T, то выражение равно M; если B = F, то выражение равно N. Если B отличен от T и F, то результат может быть произвольным.

Как и в теории множеств, в λ-исчислении можно определить упорядоченные пары:

[M, N] ≣ λx.x M N, [M, N] T ↠ M, [M, N] F ↠ N.

Цифровая система — это последовательность комбинаторов ⎡0⎤, ⎡1⎤, ⎡2⎤…, для которой существуют следование S+ и проверка на нуль Zero:

S+ ⎡n⎤ = ⎡n + 1⎤;
Zero ⎡0⎤ = T;
Zero ⎡n + 1⎤ = F.

В стандартной цифровой системе выбраны

⎡0⎤ ≣ I;
S+ ≣ λx.[F, x];
Zero ≣ λx.x T.

Цифровая система называется адекватной, если относительно нее определимы все рекурсивные функции. Для выполнения этого свойства достаточно, чтобы нашлась функция предшествования P-. Для стандартной цифровой системы это комбинатор

P- ≣ λx.x F.

Одним из основных результатов λ-исчисления является теорема о неподвижной точке: для любого F существует X, такой, что F X = X. Ее доказательство конструктивно. Пусть W ≣ λx.F (x x) и X ≣ W W. Тогда имеем X ≣ (λx. F (x x)) W = F (W W) = F X, что и требовалось доказать. Читатель, возможно, заметил одну особенность в доказательстве этой теоремы. Чтобы установить, что F X = X, мы начинаем с терма X и редуцируем его к F X, а не наоборот.

Комбинатор неподвижной точки — это терм M, такой, что для любого F имеет место M F = F (M F), то есть M F - неподвижная точка для F. Примером комбинатора неподвижной точки чаще всего служит

Y ≣ λf.(λx.f (x x)) (λx.f (x x)).

Комбинатор неподвижной точки позволяет решать задачи следующего типа: построить F, такой, что

F x y = F y x F.

Действительно, решение оказывается несложным:

F x y = F y x F следует из равенства F = λx.λy.F y x F,

а оно вытекает из F = (λf.λx.λy.f y x f) F.

Теперь положим F ≣ Y (λf.λx.λy.f y x f), и все в порядке.

В несколько измененном и дополненном виде определенный выше синтаксический сахар записан на эзотерическом языке программирования — предполагается, что программа вычисляет последнее выражение, не используя никаких операций, кроме абстракции и аппликации.
История λ-исчисления уходит в начало прошлого века. Этимология названия данного раздела математической логики, который служит основой для «computer science», следующая. Сам значек «λ» используется для одной из двух основных конструкций в созданной Черчем системе — абстракции. Оказывается, что выбор обозначения абстракции не был совершенно случайным, а сделан в противопоставление другой более ранней конструкции, которую использовали Whitehead и Russell и обозначали как «xˆ». Для новой конструкции, чтобы отличать ее от прежней, Черч заменил обозначение сначала на «∧x», а затем — на «λx», очевидно, интерпретировав первый символ как заглавную букву «Λ», для упрощения набора.

Опишем кратко систему λβη, то есть классическое бестиповое экстенсиональное λ-исчисление, вывернув наизнанку монографию Барендрегта.

Множество λ-выражений Λ строится индуктивно из переменных

x, y, z… ∈ Λ

с помощью абстракций

M ∈ Λ ⇒ λx.M ∈ Λ

и аппликаций

M, N ∈ Λ ⇒ M N ∈ Λ,

при этом аппликация лево-ассоциативна:

(M) ≣ M, M N P ≣ (M N) P.

Рефлексивное транзитивное отношение Μ ⊂ N означает, что M является подвыражением выражения N:

M ⊂ M ⊂ λx.M;
M ⊂ M N ⊃ N;
M ⊂ N ∧ N ⊂ P ⇒ M ⊂ P.

FV(M) — это множество свободных переменных в выражении M:

FV(x) ≣ {x};
FV(λx.M) ≣ FV(M) ∖ {x};
FV(M N) ≣ FV(M) ∪ FV(N).

Переменные, которые не являются свободными, называются связанными и могут быть заменены другой переменной (такое преобразование называют α-конверсией):

y ∉ FV(M) ⇒ λx.M ≣ λy.M[x := y], где M[x := N] — результат подстановки:

x[x := P] ≣ P;
y[x := P] ≣ y;
(λx.M)[x := P] ≣ λx.M;
(λy.M)[x := P] ≣ λy.M[x := P];
(M N)[x := P] ≣ M[x := P] N[x := P].

В четвертом пункте не нужно специально оговаривать условие «x ≢ y и y ∉ FV(P)», так как оно выполняется в силу соглашения о переменных: если в определенном математическом контексте встречаются термы M1,…, Mn, то подразумевается, что связанные переменные в них выбраны так, чтобы они были отличны от свободных переменных.

Если множество FV(M) пусто, то M называют комбинатором. Множество всех комбинаторов обозначают Λ0:

Λ0 ≣ {M ∈ Λ | FV(M) = ∅}.

Следующие отношения β, η и βη являются редукциями:

β ≣ {((λx.M) N, M[x := N]) | M, N ∈ Λ};
η ≣ {(λx.M x, M) | M ∈ Λ, x ∉ FV(M)};
βη ≣ β ∪ η.

Выражение, подвыражением которого является дырка, называется контекстом и обозначается C[ ], при этом C[M] — результат подстановки выражения M вместо дырки в контексте C[ ].

Если σ — редукция, то выражение M — σ-редекс, если ∃N: (M, N) ∈ σ. Также можно говорить и о σ-конверсии «=σ»:

(M, N) ∈ σ ⇒ C[Μ] →σ C[N];
M ↠σ M;
M →σ N ⇒ M ↠σ N;
M →σ N ∧ N →σ P ⇒ M ↠σ P;
∃P: M ↠σ P ∧ N ↠σ P ⇒ M =σ N.

σ-нормальной формой называют выражение Μ, если ∄Ν: M →σ Ν. В экстенсиональном λ-исчислении под редексом имеют в виду βη-редекс, а под нормальной формой — βη-нормальную форму. Говорят, что M имеет нормальную форму N, если M ↠ N. При этом βη-конверсию обычно обозначают просто «=», и это неслучайно: формально система λβη является эквациональной теорией. Так как такие теории свободны от логики, непротиворечивость в них определяется несколько иначе.

Равенством будем считать формулу вида M = N, где M, N — λ-выражения; такое равенство замкнуто, если M и N — комбинаторы. Пусть T — формальная теория, формулами которой являются равенства. Тогда говорят, что T непротиворечива (и пишут Con(T)), если в T доказуемо не любое замкнутое равенство. В противном случае говорят, что T противоречива. Одна из причин рассмотрения λβη состоит в том, что эта теория обладает определенным свойством полноты. Эквациональная теория T называется полной по Гильберту-Посту (сокращенно HP-полной), если для любого равенства M = N в языке теории T или M = N доказуемо, или T + (M = N) противоречива. HP-полные теории соответствуют максимальным непротиворечивым теориям в теории моделей для логики первого порядка.

Стратегия — это такое отображение F: Λ → Λ, что ∀M: M ↠ F(M). Для одношаговой стратегии выполняется ∀M: M → F(M). Стратегия называется нормализующей, если для любого выражения M, имеющего нормальную форму N, для некоторого числа n выполняется Fn(M) ≣ N. Левая редукция Fl — одна из самых простых одношаговых нормализующих стратегий: она заключается в выборе β-редекса, значек «λ» в котором стоит текстуально левее, чем у других β-редексов, либо левого η-редекса, если β-редексов нет. Таким образом, если два терма имеют общую нормальную форму, то с помощью левой редукции доказательство соответствующей формулы можно получить за конечное число простых шагов. Если же формула недоказуема, то либо процесс не завершается вовсе, либо он завершается на разных нормальных формах.
Вместо того, чтобы сразу браться за задачу о Тьюринг-полноте целиком, сначала посмотрим, можно ли изготовить логическую операцию «и» пригодной для процессора без команд. Наиболее известная реализация данной операции без явных сравнений содержится в синтаксическом сахаре λ-исчисления:

True = λx.λy.x;
False = λx.λy.y;
And = λp.λq.p q p.

Вот пример вычисления:

And True False = (λp.λq.p q p) True False → True False True = (λx.λy.x) False True → False.

Почему истина и ложь выбраны таким образом? Ответ на этот вопрос лежит в их обобщении — комбинаторах, которые выбирают из списка

<M0, M1, … , Mn> = λx.x M0 M1 … Mn

i-ый элемент. Такие комбинаторы выглядят следующим образом:

Pi, n = λp.p (λx0.λx1…λxn.xi).

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

void **case = (void **)NULL[0];
void **case0 = (void **)case[0];
void **case1 = (void **)case[1];

void **cond = (void **)NULL[1];
void **cond0 = (void **)cond[0];
void **cond1 = (void **)cond[1];

void **result = (void **)cond0[1];

cond0[0] = case0;
cond1[0] = case1;

Истинностное значение cond здесь предполагается в виде {X, Y}, где либо X[1] = X в случае истины, либо X[1] = Y — в противном случае. Поэтому результат окажется по адресу result[0] и будет равен либо case0, либо case1 для истины и лжи, соответственно. С учетом данных конструкций, читателю уже не должно казаться таким сложным

Упражнение. Построить логические «и», «или» и «не» или показать, что это невозможно.
Analyzing possible modifications of interaction combinators' representation suitable for uniform memory led to the subject of so-called hard combinators. In particular, trying to compose a universal equivalent of {γ, δ} such as {φ, ψ, ξ} resulted in necessary rotation of ξ with respect to its principal port in some cases. The hard combinators discovered were introduced in a quite recent same-name paper by Bechet and Lippi, namely in 2008. Some idea of Bechet most probably related to the subject was actually mentioned in the paper by Lafont, although without any details and only referencing private communication instead.

Somewhat similar to hard combinators could be of use for uniform memory implementation of interaction systems from the view point of memory-preserving property. Specifically, the total amount of cells involved in a rule for a cut should remain the same before and after reduction. This way, implementation of duplication and annihilation as well as free cells buffer appear to be explicitly embedded into a formal interaction system.

There are also some slides demonstrating the hard combinators. They are available through the following address:

http://iml.univ-mrs.fr/ldp/Seminaire/documents0607/lippi.pdf

Using Lafont's notation, the resulted system can be described as a system of interaction nets with agents of types in {0, 1, –, +}, which has been proved to be Turing-complete with the following interaction rules:

0[0(x, y), x] >< –[–(y)], 1[1(x, y), x] >< –[+(y)];
0[x, 0(y, x)] >< +[–(y)], 1[x, 1(y, x)] >< +[+(y)].
Решил подвести промежуточные итоги, сначала реконструировав свой небольшой поиск, который привел к «interaction combinators», а затем представив список статей по данной теме.

Постановка задачи была такой, что требовалось реализовать экстенсиональную версию оптимальной редукции для Тьюринг-полного чистого бестипового λ-исчисления на основе однородной памяти с работой в реальном времени и без потери памяти при NC = 2. Я начал решать эту задачу, познакомившись с монографией по оптимальной редукции. Так как оригинальный алгоритм Лэмпинга, как и основные его варианты, является «interaction system» с бесконечными (из-за наличия индексов) наборами типов агентов и правил взаимодействия, требование работы в реальном времени выполняться не могло. Поэтому я сосредоточился на единственном варианте оптимальной редукции с конечным набором операторов, который был представлен в монографии, — это нотация с помощью шин.

Далее, я заметил, что в некоторых случаях поведение разделяющей ноды может симулировать работу как брекетов и круассанов, так и самой ширины шины разделяющей ноды. Это подтолкнуло меня к попытке построить систему с поляризованным представлением λ-выражений и редукциями γ, β и η. Различные варианты этой системы оказались некорректными, однако, их изучение дало необходимые ключевые слова, чтобы продолжить поиск.

Одной из «interaction systems» с конечными наборами типов агентов и правил взаимодействия оказался самый эффективный, по крайней мере, на 2004 год, вариант KCLE [1]. Тем не менее, огромное количество типов и правил данной системы затрудняло ее реализацию в однородной памяти. Заметив в [2, 3, 4] использование, среди прочих, агентов γ и δ с правилами взаимодействия γ[δ(a, b), δ(c, d)] >< δ[γ(a, c), γ(b, d)], δ[x, y] >< δ[x, y] и γ[x, y] >< γ[y, x], я стал копать в сторону их происхождения. Оказалось, что как нотация для правил выше, так и сама система {γ, δ} принадлежат Yves Lafont. Называемая «interaction combinators», она была введена и подробно рассмотрена в одноименной статье [5]. В частности, доказывается, что система {γ, δ} полна по Тьюрингу.

Таким образом, оставалось лишь изучить способы представления λ-выражений с помощью исключительно «interaction combinators» [6], а также дополнительных правил преобразования за формальными пределами «interaction nets», которые бы заменяли η-редукцию в λ-исчислении [7]. То есть на данный момент вопрос остается лишь в выборе представления «interaction combinators» с дополнительными η-правилами в однородной памяти. После этого можно продолжить работу над проектом MLC (Macro Lambda Calculus), основной целью которого является отделение операций над данными от «control flow» постановкой барьера ввода-вывода по старой схеме Haskell через прерывания по обращению к памяти.

1. Ian Mackie. Efficient λ-Evaluation with Interaction Nets (2004).
2. Ian Mackie. Static analysis of interaction nets for distributed implementations (1997).
3. François-Régis Sinot. Token-Passing Nets: Call-by-Need for Free (2005).
4. Sylvain Lippi. Encoding left reduction in the λ-calculus with interaction nets (2002).
5. Yves Lafont. Interaction Combinators (1997).
6. Ian Mackie, Jorge Sousa Pinto. Compiling the λ-calculus into Interaction Combinators (1998).
7. Maribel Fernandez, Ian Mackie. A Theory of Operational Equivalence for Interaction Nets (2000).
Одним из наиболее компактных способов описания правил «interaction nets» является эзотерический язык программирования, предложенный в статье 1989 года «Interaction nets» (Lafont) — см. стр. 104. Он основан на двух наблюдениях. Во-первых, левая часть любого правила всегда содержит лишь два агента, которые связаны своими главными портами. Во-вторых, правая часть каждого правила никогда не содержит редексов, из чего следует, что дополнительные порты обоих взаимодействующих агентов в общем случае являются корнями деревьев, листья которых связаны между собой произвольным образом. Поэтому описанию подлежат лишь сами деревья, а также связи между листьями.

В качестве примера возьмем первое правило для системы с агентами типов γ и δ. Сначала оттолкнемся от более простой избыточной нотации, не требующей дополнительных пояснений, в которой первый аргумент агента соответствует главному порту:

γ(x, y, z), δ(x, v, w) → δ(y, a, b), δ(z, c, d), γ(v, a, c), γ(w, b, d).

Воспользуемся первым наблюдением:

γ[y, z] >< δ[v, w] → δ(y, a, b), δ(z, c, d), γ(v, a, c), γ(w, b, d).

Теперь заметим, что каждый главный порт в правой части использует один из дополнительных портов в левой. Значит, мы можем без потери информации записать агенты правой части на местах соответствующих дополнительных портов левой:

γ[δ(a, b), δ(c, d)] >< δ[γ(a, c), γ(b, d)].

Два других правила системы записываются проще, так как соответствующие деревья с корнями на дополнительных портах левой части состоят каждое лишь из одного листа:

δ[x, y] >< δ[x, y], γ[x, y] >< γ[y, x].
А запишу-ка я просто как думается, ведь все равно не знаю, где такое есть в литературе и как правильно называется. Мысли, собственно говоря, об отрицаниях и общности в человеческих языках в связи с конструктивной математикой с пустым набором аксиом.

Посылка провокационная. Можно долго обсуждать. Если коротко, то все фразы, содержащие отрицание, кроме идиом и иронии, ложны, а все остальные высказывания правдивы. Дело в том, что отрицание вводит общности по времени, месту, смыслам и многому другому, и как ее не ограничивай, найдется интерпретация и обстоятельства, при которых утверждение с отрицанием окажется неверным, а значит, и в общем случае было неверным.

С предложениями без отрицаний все наоборот. Там вводится существование, какую общность вроде места и времени не накладывай, так как найдется интерпретация (в том числе и для самих слов, обозначающих общность) и обстоятельства, где фраза будет верна, пусть даже выдуманные или откровенно фантастические.

Это что-то вроде конструктивного подхода, когда нет базовых аксиом, где можно лишь показать, что объект существует, предъявив его построение, хоть какое-нибудь, не обязательно даже полезное или вообще имеющее какое-то отношение к действительности. А говорить о несуществовании чего-либо нельзя, ибо мало ли чего есть в определенных системах аксиом. Вон, нечеткая логика всякая.
Из комментариев к предыдущей записи вынесу, пожалуй, пару точек зрения. Одна из них заключается в счетности непротиворечивых теорий независимо от аксиоматики, включая те, что аксиоматизируют несчетные множества; другая же — в недоумении, почему мы пользуемся классическим матаппаратом, чтобы показать неконструктивность континуума.

На первую ответ простой: аксиоматизировать объект не значит построить его. Континуум продолжит быть просто названием, символом, буковкой, которую мы переставляем в логических выводах туда-сюда. Как невидимый единорог, в отношение которого тоже можно и теорем счетное множество доказать, и диссертацию защитить. Никто не мешает.

Другое дело с конструктивными объектами. Любой из них можно определить индуктивно с помощью правил как при описании нового языка, без аксиоматики. Известно, что любая конструкция, которой можно в общем случае научить оперировать другого человека или машину, неизбежно окажется определимой таким образом.

На вторую же точку зрения ответ чуть сложнее. Начнем с того, что выбор теории, доказательство ее непротиворечивости, построение модели, выбор объекта для построения (в отличие от предъявления этого объекта) — необходимые для работы с современной математикой вещи. Они, естественно, лежат за пределами чистой конструктивной математики и логики первого порядка. К примеру, определить конструктивные вещественные числа, конечно, можно, но выбрать этот объект случайно и привязать его к природе невозможно.

Не все знают, что такое λ-исчисление. Чаще всего с этим термином связывают систему λΚβη, иногда типизированные ее варианты. Однако, более общее значение термина — это раздел математической логики, занимающийся изучением целого класса подобных систем и их свойств, центральное место среди которых, действительно, занимает бестиповая λΚβη. Более точно, λ-исчисление — это применение классического матаппарата к изучению λ-теорий и их моделей.

Отсюда виден ответ: чисто конструктивная математика с заранее известными объектами и операциями над ними достаточна для инженерных задач как язык описания и способ вычисления, ровно который возможно автоматизировать с помощью программ компьютерной алгебры. Однако, чтобы вообще говорить о конструктивной математике и заниматься ее развитием, необходим классический матаппарат, и в этом нет никакого противоречия: именно он дает нам возможность отличить конструктивные определения объектов от неформальных.

Profile

Anton Salikhmetov

November 2018

S M T W T F S
    123
45678 910
11121314151617
18192021222324
252627282930 

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Aug. 14th, 2025 08:30 pm
Powered by Dreamwidth Studios