S = [a];
...
3.9. Определите отношение
разбиениесписка( Список, Список1, Список2)
так, чтобы оно распределяло элементы списка между двумя списками Список1
и Список2
и чтобы эти списки были примерно одинаковой длины. Например:
разбиениесписка( [а, b, с, d, e], [a, с, e], [b, d]).
3.10. Перепишите программу об обезьяне и бананах из главы 2 таким образом, чтобы отношение
можетзавладеть( Состояние, Действия)
давало не только положительный или отрицательный ответ, но и порождало последовательность действий обезьяны, приводящую ее к успеху. Пусть Действия
будет такой последовательностью, представленной в виде списка ходов:
Действия = [ перейти( дверь, окно),
передвинуть( окно, середина),
залезть, схватить ]
3.11. Определите отношение
линеаризация( Список, ЛинейныйСписок)
где Список
может быть списком списков, а ЛинейныйСписок
— это тот же список, но 'выровненный' таким образом, что элементы его подсписков составляют один линейный список. Например:
?- линеаризация( [а, d, [с, d], [], [[[e]]], f, L).
L = [a, b, c, d, e, f]
3.3. Операторная запись (нотация)
В математике мы привыкли записывать выражения в таком виде:
где + и * — это операторы, а
+( *( 2, а), *( b, с) )
Рис. 3.6. Представление выражения
Поскольку мы обычно предпочитаем записывать такие выражения в привычной инфиксной форме операторов, Пролог обеспечивает такое удобство. Поэтому наше выражение, записанное просто как
2*а + b*с
будет воспринято правильно. Однако это лишь внешнее представление объекта, которое будет автоматически преобразовано в обычную форму прологовских термов. Такой терм выводится пользователю снова в своей внешней инфиксной форме.
Выражения рассматриваются Прологом просто как дополнительный способ записи, при котором не вводятся какие-либо новые принципы структуризации объектов данных. Если мы напишем а + b
, Пролог поймет эту запись, как если бы написали +(а, b)
. Для того, чтобы Пролог правильно воспринимал выражения типа а + b*с
, он должен знать, что *
связывает сильнее, чем +
. Будем говорить, что +
имеет более низкий приоритет, чем *
. Поэтому верная интерпретация выражений зависит от приоритетов операторов. Например, выражение а + b*с
, в принципе можно понимать и как
+( а, *( b, с) )
и как
*( +( а, b), с)
Общее правило состоит в том, что оператор с самым низким приоритетом расценивается как главный функтор терма. Если мы хотим, чтобы выражения, содержащие +
и *
, понимались в соответствии с обычными соглашениями, то +
должен иметь более низкий приоритет, чем *
. Тогда выражение а + b*с
означает то же, что и а + (b*с)
. Если имеется в виду другая интерпретация, то это надо указать явно с помощью скобок, например (а+b)*с
.
Программист может вводить свои собственные операторы. Так, например, можно определить атомы имеет
и поддерживает
в качестве инфиксных операторов, а затем записывать в программе факты вида:
питер имеет информацию.
пол поддерживает стол.
Эти факты в точности эквивалентны следующим:
имеет( питер, информацию).
поддерживает( пол, стол).
Программист определяет новые операторы, вводя в программу особый вид предложений, которые иногда называют
:- op( 600, xfx, имеет).
Такая запись сообщит Прологу, что мы хотим использовать 'имеет' в качестве оператора с приоритетом 600 и типом 'xfx
', обозначающий одну из разновидностей инфиксного оператора. Форма спецификатора 'xfx
' указывает на то, что оператор, обозначенный через 'f
', располагается между аргументами, обозначенными через 'х
'.
Обратите внимание на то, что определения операторов не содержат описания каких-либо операций или действий. В соответствии с принципами языка
Имена операторов это атомы, а их приоритеты — точнее, номера их приоритетов — должны находиться в некотором диапазоне, зависящем от реализации. Мы будем считать, что этот диапазон располагается в пределах от 1 до 1200.[1]
Существуют три группы типов операторов, обозначаемые спецификаторами, похожими на xfx
:
(1) инфиксные операторы трех типов:
xfx xfy yfx
(2) префиксные операторы двух типов:
fx fy
(3) постфиксные операторы двух типов:
хf yf