Опубликован: 19.03.2004 | Уровень: специалист | Доступ: платный
Лекция 11:

Варианты, последовательности, множества

< Лекция 10 || Лекция 11: 123 || Лекция 12 >
Аннотация: Описаны приемы организации недетерминированных вычислений в рамках функционального стиля программирования. Реализация программ с возвратами, перебор вариантов, откат влекут за собой расширение семантического базиса механизмами обработки прерываний. Анализируется соответствие точности решения задач и уровня их изученности. Исследуются связь диагностической интерпретации и средств логического программирования. Обработка множеств, последовательностей и хэш-таблиц дает материал для простых примеров.

Недетерминированные процессы

Есть мнение, что однозначное решение задачи в виде четкого алгоритма над хорошо организованными структурами и упорядоченными данными — результат аккуратной, тщательной работы, пытливого и вдумчивого изучения класса задач и требований к их решению.

Эффективные и надежные программы в таких случаях — естественное вознаграждение.

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

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

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

Обычно понятие алгоритма и программы связывают с детерминированными процессами.

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

По смыслу выбор варианта похож на выбор произвольного элемента множества.

{ a | b | c } = э { a, b, c }

Чтобы такое понятие промоделировать обычными функциональными средствами, нужны дополнительные примитивы. Например, чтобы определить выбор произвольного элемента из списка L, можно представить рекурсивное выражение вида:

(любой L) = { ( CAR L)
                   | (любой (CDR L)) }

Если варианты в таком выражении рассматривать как равноправные компоненты, то не ясно, как предотвратить преждевременный выбор пустого списка при непустом перечне вариантов.

Чтобы решить эту задачу, вводится специальная форма ESC ( ТУПИК ), действие которой заключается в том, что она как бы "старается" по возможности не исполняться. Иными словами, при выборе вариантов предпочитаются варианты, не приводящие к исполнению формы ESC. (Такая же проблема возникает при обработке пустых цепочек в грамматиках. Аналогичным образом эта проблема решена при моделировании процессов интерпретированными сетями Петри [ 17 ] — соглашением о приоритете раскрашенных переходов в сравнении с пустыми.)

Уточненное таким образом определение выбора произвольного элемента списка можно представить формулой вида:

(любой L) = { (CAR L)
                   | (любой (CDR L))
                   | (if (nl L) ESC) }

В какой-то момент L становится пустым списком, и его разбор оказывается невозможным. Тогда действует ESC.

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

Другие построения, характерные для теории множеств: { x | P(X) } — множество элементов, обладающих свойством P.

Определение вида

(F L) = {(if (P ( CAR L )) 
             (CONS ( CAR L) (F ( CDR L))) ) 
        | (if (nl L) ESC) }

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

(F L) = (ALL {(if (P ( CAR L )) 
                  (CONS ( CAR L) (F ( CDR L)) ) ) 
             | (if (nl L) ESC) } )

Пересечение множеств A и B

(ALL ( LAMBDA (x y) { (if (= x y) x)
                    |
                    ESC }) (любой A) (любой B) )

Логические связки

Логика McCarthy (компьютерная)

a & b

(if (not a) NIL b)

b вычисляется лишь при истинном a, что результативно, но не всегда соответствует интуитивным ожиданиям (логика, предложенная в свое время McCarthy, позволяет добиться высокой эффективности). Математически более надежны варианты, исключающие зависимость от порядка перебора:

Более надежны варианты, исключающие зависимость от порядка перебора:

(( ALL( LAMBDA x { (if (not x) NIL ) 
                                                                     | ESC })
                                                                               {a | b} )

Если a и b оба истины, то получается ESC. Такое значение отличается от NIL, что работает как истина.

Аналогичная проблема возникает при построении ветвлений:

(cond (p1 e1) (p2 e2 ) ... )

( LAMBDA L {(COND ((eval(caar L)AL) 
                    (eval(cadr L)AL) )) 
            | ESC })
                   ( любой ((p1 e1) (p2 e2) ... ) ) )

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

a+b+c = (a+b)+c = a+(b+c) = (a+c)+b

((LAMBDA (x y z) {(if (< (+ x y) K) (+ (+ x y) z))
                           | ESC} )
                                      {(a b c) | (b c a) | (c a b)} )

В книге Хендерсона приведено обобщение абстрактной машины, поддерживающее на базовом уровне работу с вариантами с использованием дополнительного дампа, гарантирующего идентичность состояния машины при переборе вариантов [ 3 ] .

< Лекция 10 || Лекция 11: 123 || Лекция 12 >
Дарья Федотова
Дарья Федотова
Сергей Березовский
Сергей Березовский

В рамках проф. переподготовки по программе "Программирование"

Есть курсы, которые я уже прошел. Но войдя в курс я вижу, что они не зачтены (Язык Ассемблера и архитектура ЭВМ, Программирование на С++ для профессионалов). Это как?

Алина Ленкова
Алина Ленкова
Россия, Ставрополь, СФ МГУПИ, 2014
Валерий Ромашов
Валерий Ромашов
Россия