Show page source of ExSaru #35274

[FrontPage ← 先頭のページに戻る]


== デカルト言語のプログラム:サルとバナナ


人工知能風のプログラムをご紹介しましょう。

昔からある有名な問題です。



{{{

 天井にバナナが紐で結んで吊るしてあります。


 一匹の猿がいます。

 猿はバナナを食べたいのですが、背伸びしても跳ねても届きません。


 部屋の角には、棒が落ちています。


 隣の部屋には大きな箱があります。


 猿は、バナナを取れるでしょうか?

}}}


この問題を、デカルト言語で猿を作って解かせてみましょう。



注意) この例題は、最新のdescartes-0.6.0でないと動作しません。



=== 1. 世界の状態の表現


この世界の状態を以下のようなリストで表すこととします。


 (状態 猿の位置 猿の高さ 箱の位置 猿の持ち物)


猿の最初の状態は、このように表せます。


 (状態 "スタート地点"  地面 "隣の部屋" 手ぶら)


猿は、「スタート地点」の「地面」にいて、箱は「隣の部屋」にあり、
猿は「手ぶら」です。


=== 2. 猿の行動による状態の変化


猿のとれる行動は以下の通りです。


 - 棒を使ってバナナを落として、バナナをつかむ

 - 部屋の角 で棒を拾う

 - 箱に登る

 - 箱を押す

 - 歩いて移動する

 - 棒を投げる

 - 箱を持ち上げる



猿の行動は、現在の状態を変化させて、新しい状態に変化させます。

これは次のようなプログラムで表現します。


 <action 行動者 行動

    前の状態

    次の状態 >;



例えば、「#who が、#place1 から #place2 まで歩く」は、こうなります。


 <action #who (#who が、#place1 から #place2 まで歩く)

   (状態 #place1 地面 #place3 #Hand) 

   (状態 #place2 地面 #place3 #Hand)>;


他の行動についてもどうなるかちょっと考えてみてください。
(「6. 全体ソース」に解答があります。)


=== 3. 猿の思考ルーチン

猿はオブジェクトとして実装します。


{{{

::<猿
	<考える #st>			// (1)
		<考える #st () #rep>
		<printlistnl #rep>
		;

	<考える (状態 _ _ _ バナナ) #rep #rep>; // (2)
	<考える #State1 #rep1 #rep>		// (3)
		<self #who>
		<action #who #Operate #State1 #State2> 
		<append #rep2 #rep1 (#Operate)>
		<考える #State2 #rep2 #rep>
		;
>;

}}}

思考ルーチンは、3つの部分でできています。

(1) 1つの引数を持つ <考える> 述語は、最初の状態を #stに設定して

 2つの引数を持つ <考える> 述語を呼び出し、

 最後にprintlistnlで結果を表示する部分です。


(2) 状態の「猿の持ち物」が、バナナになっています。

 つまり、これは最終的な目的の状態を表します。

 第2、第3引数の#repには、(3)で後述する猿の行動のログが入っています。


(3) selfは、オブジェクトの名前を獲得します。

 actionで、猿の行動を決めます。

 appendで、猿の行動#Operateをロギングしていきます。

 最後の、<考える> で新しい状態#State2を元に次の行動を模索します。


=== 4. ゴリラとチンパンジー

猿をオブジェクトとして実装したので、これを継承機能を使うと
別のオブジェクトに継承させることができます。

{{{

::<ゴリラ
	inherit 猿;
>;


::<"チンパンジー"
	inherit ゴリラ;
>;

}}}

ゴリラは猿を継承しています。

チンパンジーは、ゴリラを継承しています。

これで、ゴリラとチンパンジーも猿と同様の思考をして見せます。


=== 5. 実行

さて、お待ちかねの実行結果を表示します。

ゴリラとチンパンジーについては、同じ行動をさせても面白くないので
最初の地点と箱の置き場所を変えてあります。


{{{

$ ./descartes example/saru/sarubanana3-sjis
 猿 が、 スタート地点 から 部屋の角 まで歩く
 猿 が、部屋の角 で棒を拾う
 猿 が、 部屋の角 から 隣の部屋 まで歩く
 猿 が、箱を 隣の部屋 から バナナの下 まで押す
 猿 が、 バナナの下 で箱に登る
 猿 が、棒を使ってバナナを落として、バナナをつかむ
result --
        ::猿 <考える (状態 スタート地点 地面 隣の部屋 手ぶら)>
-- true

 ゴリラ が、 戦場 から 部屋の角 まで歩く
 ゴリラ が、部屋の角 で棒を拾う
 ゴリラ が、 部屋の角 から 敵地 まで歩く
 ゴリラ が、箱を 敵地 から バナナの下 まで押す
 ゴリラ が、 バナナの下 で箱に登る
 ゴリラ が、棒を使ってバナナを落として、バナナをつかむ
result --
        ::ゴリラ <考える (状態 戦場 地面 敵地 手ぶら)>
-- true

 チンパンジー が、 木星 から 部屋の角 まで歩く
 チンパンジー が、部屋の角 で棒を拾う
 チンパンジー が、 部屋の角 から 月 まで歩く
 チンパンジー が、箱を 月 から バナナの下 まで押す
 チンパンジー が、 バナナの下 で箱に登る
 チンパンジー が、棒を使ってバナナを落として、バナナをつかむ
result --
        ::チンパンジー <考える (状態 木星 地面 月 手ぶら)>
-- true

}}}

ゴリラは元特殊部隊員で、チンパンジーは木星帰りで箱に触ったら目覚めてしまったという設定です。



=== 6. 全体ソース

このソースは、ダウンロードにあるリリースされているファイルの中のexample/saruの下にもあります。

---

{{{

<append #X () #X >;
<append (#A : #Z) (#A : #X)  #Y>
	<append #Z #X #Y >;

<action #who (#who が、棒を使ってバナナを落として、バナナをつかむ)
	(状態 バナナの下 箱の上 バナナの下 棒 ) 
	(状態 バナナの下 箱の上 バナナの下 バナナ)>;
<action #who (#who が、部屋の角 で棒を拾う)
	(状態 部屋の角 地面 #place2 手ぶら)
	(状態 部屋の角 地面 #place2 棒)>;
<action #who (#who が、#place で箱に登る)
	(状態 #place 地面   #place #Hand) 
	(状態 #place 箱の上 #place #Hand)>;
<action #who (#who が、箱を #place1 から #place2 まで押す)
	(状態 #place1 地面 #place1 #Hand) 
	(状態 #place2 地面 #place2 #Hand)>;
<action #who (#who が、#place1 から #place2 まで歩く)
	(状態 #place1 地面 #place3 #Hand) 
	(状態 #place2 地面 #place3 #Hand)>;
<action #who (#who が、棒を投げる)
	(状態 #place1 地面 #place2 棒)
	(状態 #place1 地面 #place2 手ぶら)>;
<action #who (#who が、箱を持ち上げる)
	(状態 #place1 地面 #place1 #Hand)
	(状態 #place1 地面 #place1 #Hand)>;

::<猿
	<考える #st>
		<考える #st () #rep>
		<printlistnl #rep>
		;

	<考える (状態 _ _ _ バナナ) #rep #rep>;
	<考える #State1 #rep1 #rep>
		<self #who>
		<action #who #Operate #State1 #State2> 
		<append #rep2 #rep1 (#Operate)>
		<考える #State2 #rep2 #rep>
		;
>;



? ::猿 <考える (状態 "スタート地点"  地面 "隣の部屋" 手ぶら)>;


::<ゴリラ
	inherit 猿;
>;


? ::ゴリラ <考える (状態 戦場 地面 敵地 手ぶら)>;


::<"チンパンジー"
	inherit ゴリラ;
>;


? ::"チンパンジー" <考える (状態 木星 地面 月 手ぶら)>;

}}}

---