Реализация комбинаторного исчисления

Концепция

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

pair a b c → c a b
true a b → a
first a → a true

Затем пользователь может ввести first (pair a b), которое постепенно уменьшается в соответствии с ранее определенными правилами:

first (pair a b)
→ pair a b true
→ true a b
→ a

Также могут быть определены другие комбинаторы, например используемые в исчислении комбинаторов SKI:

S x y z → x z (y z)
K x y → x
I x → x

Комбинатор идентификаторов также может быть определен в терминах первых двух комбинаторов с помощью I → S S K K, I → S K (K K) или I = S K x. Универсальный комбинатор iota может быть определен следующим образом:

ι x → x S K

Надеюсь, эти примеры иллюстрируют то, что я пытаюсь сделать.

Реализация

Я пытаюсь реализовать это с помощью сокращения графа и система перезаписи графов. Пусть tree будет типом данных, определяемым рекурсивно

tree = leaf | (tree tree)

Это бинарное дерево, узлы которого могут быть либо листьями (конечными узлами), либо ветвями (внутренними узлами), состоящими из пары поддеревьев. Ветви представляют применение термина к другому термину, а листья представляют комбинаторы и аргументы. Пусть rule будет типом данных, определенным

rule = (tree tree)

Это соответствует правилу редукции, которое преобразует левое дерево в правое дерево (a → b). Затем список rules может быть определен как

rules = rule | (rule rules)

По сути, при оценке такого выражения, как pair a b c → c a b, интерпретатор строит дерево формы (((pair a) b) c), соответствующее левой части, дерево формы ((c a) b), соответствующее правой части, строит пару обоих деревьев, соответствующих rule ( где a,b,c каким-то образом указаны как произвольные параметры и не обязательно комбинаторы или терминальные символы), и добавляет эту пару в список rules. При редукции выражения вида first (pair a b) интерпретатор строит соответствующее дерево (first ((pair a) b)) и применяет следующие правила редукции:

(first ((pair a) b))
→ (((pair a) b) true)
→ ((true a) b)
→ a

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

struct tree_t {
    bool is_leaf;
    union {
        char* symbol;
        struct {
            tree_t* left;
            tree_t* right;
        };
    };
};

Функция сопоставления с образцом может быть реализована как

bool matches(tree_t* pattern, tree_t* replacement) {
    if (pattern -> is_leaf && replacement -> is_leaf)
        //do stuff, return a boolean
    else if (pattern -> is_leaf && replacement -> is_branch)
        //do stuff, return a boolean
    else if (pattern -> is_branch && replacement -> is_leaf)
        //do stuff, return a boolean
    else if (pattern -> is_branch && replacement -> is_branch)
        return matches(pattern -> left, replacement -> left) && matches(pattern -> right, replacement -> right);
        //The above tests for equality recursively by testing for equality in each subtree.
}

Однако я не уверен, как реализовать важные детали этого процесса, в том числе:

  1. Сопоставление входного дерева с деревом LHS правила редукции.
  2. Преобразование входного дерева в RHS-дерево правила редукции с сохранением параметров (которые могут быть листьями или ветвями) и перемещением их в соответствующие места.

Я считаю, что сопоставление с образцом на узле будет включать проверку левого дочернего и правого дочерних элементов узла и так далее, пока не будут достигнуты конечные узлы. Кто-нибудь знает программу или учебник в Интернете, в котором реализована аналогичная концепция на C, и у которой я мог бы учиться? Я вообще на правильном пути в подходе к проблеме с помощью этого метода, или есть более простой способ?


person user76284    schedule 10.06.2014    source источник
comment
amazon.com/   -  person SK-logic    schedule 18.06.2014
comment
Вы должны пройти по ветке LHS до тех пор, пока следующий LHS не станет узлом применения. Затем выберите действие с токеном, хранящимся в LHS. Вы можете увидеть пример такой реализации здесь: sourceforge.net/projects/dslengine   -  person SK-logic    schedule 18.06.2014


Ответы (1)


Вы должны взять его в два отдельных шага. Сопоставитель шаблонов сопоставляет шаблон с деревом и строит словарь, отображающий переменные в шаблоне на значения в дереве.

Затем вы передаете этот словарь отдельной функции, которая выполняет замену, заменяя переменные их значениями из словаря.

Подход к сопоставлению с образцом, описанный в SICP, будет прекрасно работать в C, хотя вам может быть проще использовать изменяемую структуру данных для словаря. См. https://mitpress.mit.edu/sicp/full-text/sicp/book/node99.html

person Andru Luvisi    schedule 15.07.2015