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_

СИИМ) О