Atdoor onfloor atwindow has riot
Рис. 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_
СИИМ) О