Рис. 2.10. Начальное состояние мира обезьяны, представленное как структурированный объект. Четырьмя его компонентами являются: положение обезьяны на плоскости, положение обезьяны в пространстве (на ящике или на полу), положение ящика, отсутствие или наличие у обезьяны банана
Данную проблему можно рассматривать как игру с одним участником. Формализуем правила этой игры. Во-первых, целью этой игры является ситуация, в которой обезьяна имеет банан; иными словами, любое состояние, в котором последним компонентом является информация о наличии банана: state { _, _,, has)
Во-вторых, необходимо рассмотреть, каковы допустимые действия, после выполнения которых мир переходит из одного состояния в другое. Это — действия следующих четырех типов.
1. Схватить банан (grasp).
2. Залезть на ящик (climb).
3. Передвинуть ящик (push).
4. Перейти из одного места в другое (walk).
Не все действия возможны во всех возможных состояниях мира. Например, действие "схватить банан" возможно, только если обезьяна стоит на ящике непосредственно под бананом (который находится в середине комнаты) и еще не схватила ба-
Глава 2, Синтаксис и значение программ Prolog
нан. Эти правила можно формально представить на языке Prolog в виде следующего трехместного отношения, обозначенного как move: move(Statel, Move, Stated
Поэтому три параметра этого отношения определяют действие следующим образом:
Statel ------------ ► State2
Move
Statel — это состояние до выполнения действия, Move — выполняемое действие и State2 — состояние после выполнения действия.
Действие grasp с его обязательной предпосылкой, определяемой состоянием перед этим действием, может быть определено с помощью следующего предложения:
mcvet state ( middle, onbox, middle, hasnot), I Перед выполнением действия
grasp, \ Действие
sta-.c-: middle, cnbcx, middle, has]). % После выполнения действия
Этот факт говорит о том, что после действия, в результате которого обезьяна получает банан, она остается на ящике в середине комнаты.
Аналогичным образом можно выразить тот факт, что обезьяна может передвигаться по полу из любого горизонтального положения Posl в любое положение Pos2. Обезьяна может выполнять это действие независимо от положения ящика, а также от того, схватила она банан или нет. Все эти условия могут быть определены с помощью следующего факта Prolog:
move( state { Posl, onfloor, Box, Has),
walk( Posl, Pos2), % Перейти из Posl в Pos2
state! Pos2, onfloor. Box, Has)).
Обратите внимание, что это предложение говорит о многом, например о следующем:
• было выполнено действие "перейти из некоторой позиции Posl в некоторую позицию Pos2";
• обезьяна находится на полу до и после выполнения этого действия;
• ящик находится в некоторой точке Box, которая остается неизменной после этого действия;
• состояние "наличия банана"Наз после этого действия остается неизменным.
Данное предложение фактически определяет целое множество возможных действий, поскольку оно применимо к любой ситуации, которая согласуется с указанным состоянием, предшествующим этому действию. Поэтому подобную спецификацию иногда называют также схемой движения. Такие схемы можно легко запрограммировать на языке Prolog с использованием переменных Prolog.
Другие два типа действий, push и climb, можно определить аналогичным образом.
Рассматриваемая программа должна отвечать на вопросы такого основного типа: может ли обезьяна в некотором начальном состоянии State получить банан? Такие вопросы можно формально представить в виде следующего предиката: canget < State)
Здесь параметр State представляет собой одно из состояний мира обезьяны. Программа определения предиката canget может быть основана на двух приведенных ниже наблюдениях.
1, Для любого состояния, в котором обезьяна уже имеет банан, предикат canget,
безусловно, должен быть истинным; в таком случае не требуются какие-либо
действия. Это соответствует следующему факту Prolog:
canget(state(_, _, _, has}).
2. В других случаях необходимо выполнить одно или несколько действий. Обезь
яна может получить банан в любом состоянии Statel, если есть некоторое
действие Move для перехода из состояния Statel в некоторое состояние
State2, такое, что обезьяна затем может получить банан в состоянии State2
64 Часть!. Язык Prolog
(выполнив от нуля и больше действий). Этот принцип проиллюстрирован на рис. 2.11. Предложение Prolog, которое соответствует этому правилу, приведено ниже. canget(Statel): -
move[ Statel, Move, Statel),
canget (State2).
На этом завершается разработка программы, которая показана в листинге 2.3.
Формулировка предиката canget является рекурсивной и аналогична формулировке отношения predecessor, описанного в главе 1 (сравните рис. 1.7 и 2.11). Такой принцип используется в языке Prolog снова и снова.
Move _
Statel __ State2 ^^._ „ __ &tote_
СИИМ) О