Prolog実践入門 - AIに特化した老舗言語

#はじめに
この記事は[フューチャーアーキテクト Advent Calendar 2015](http://qiita.com/advent-calendar/2015/future)の12/22です。

弊社副社長も書いていたと公言するPrologに関して書きます！
私も大学生の時に書いていたので、Prologとは？から書き始めたいと思います。

#Prologとは？
Prologは1972年に登場した老舗の非手続き型のプログラミング言語であり、主にAIに特化して作られています。Prologという名前の由来は、**PRO**gramming in **LOG**icからきています。その名の通りPrologでは論理的に物事を解釈するようにプログラムを書きます。



#Prologなんてオワコンじゃない？
Go言語やRustなどから比べると40年近く前に登場した言語であり、AIに特化した言語ということもあり、知名度が低く、利用者も少ないですが、教育機関(大学など)で主として論理学の教材として利用され続けているのです！

**結局オワコンじゃん！？**って思った方・・・そんなことないんです。


最近の有名なProlog利用事例は、何と言ってもあのソフトバンクの[**Pepper**](http://www.softbank.jp/robot/consumer/products/)の開発にPrologが使われているということです！Pepperが言語を処理して会話する時のプログラムはPrologで書かれているそうです。
[参考URL:なぜロボットに感情が必要なのか、ソフトバンクの熟慮（上）](http://itpro.nikkeibp.co.jp/atcl/column/14/090100053/082700077/?ST=bigdata&P=1)

#Prologのプログラムを構成する要素
Prologのプログラムを構成する要素は3つです。
1. 事実：物事の事実を宣言すること
2. 規則：物事との関係に関しての規則を定義すること
3. 質問：物事との関係について質問すること

下記に3つの要素の具体的な例を示します。

###事実とは
「鈴木さんは東京に住んでいる」というような事が**事実**です。英語にすると「Suzuki lives in Tokyo.」です。これをPrologのコードにすると、下記のようになります。
`live(suzuki, tokyo).`

###規則とは
複数の事実を用いて、一つの事実を表すことを**規則**と言います。
例えば、下記は「エンジニアであれば、人間である」という意味になります。
エンジニアとは、人間の職業を指しますよね。つまり◯◯さんはエンジニアである。という事実があれば、それは◯◯さんは人間であるという事も意味しますね。
`engineer(X) :-human(X).`


###質問とは
Prologに対して、質問を投げることを言います。
Prologは質問に合致する事実があれば "yes" と回答し、なければ "no" と 回答します。 
`?- live(suzuki,tokyo). ←入力
yes                    ←Prologの回答`
(上記の結果を得るためにはlive(suzuki, tokyo)という事実をあらかじめPrologに登録しておく必要があります。)


#Prologの実行環境準備
今回は、Prologの実行環境として一番有名な[SWI-Prolog](http://www.swi-prolog.org/)という処理系を使用します。環境構築には大きく２つの方法があります。１つ目はSWI-Prologのページにアクセスし、バイナリファイルをダウンロードしてインストーラ使う方法。２つ目はパッケージ管理ツールを用いてインストールを行う方法です。

今回はパッケージ管理ツール(Homebrew)を用いてインストールを行いました。

■環境
　OS X 10.9.3

1. コマンドを打つ   
`brew install swi-prolog`   
これだけです！   

[参考：HomebrewでのSWI-Prologインストール方法](http://www.swi-prolog.org/build/macos.html)

環境構築簡単ですね。Homebrew良いですね！
あとはPrologのコードを書くだけです！


#実践！Prologでゼブラパズル解いてみた
##ゼブラパズルって何？
そもそもゼブラパズルって何？という方が多いと思いますが、ゼブラパズルは推理パズルの一つであり、世界の人口の中で２%しか解けないと言われるパズルです。そんなパズルをPrologを使って解いてみようと思います。
[参考：ゼブラパズル](https://en.wikipedia.org/wiki/Zebra_Puzzle)

##問題（今回は分かりやすくするためにゼブラパズルを少し簡略化しました）
1. 家が３軒あります。その３軒の家はそれぞれ赤・青・緑で塗られています。そしてその住人は、それぞれ異なる国籍で、それぞれ異なるペットを買っています。
2. イギリス人は赤い家に住んでいます。
3. スペイン人は犬を飼っています。
4. 日本人は、猫を飼っている人の右側に住んでいます。
5. 猫を飼っている人は青色の家の左に住んでいます。

**誰がシマウマを飼っているでしょう？**

みなさん、解けましたか！？
・・・

私は解けませんでした汗
ではPrologでコードを書き、解いていきます。

まず、問題文を読み解くところから始めます。
■３人の人が並んで住んでいるということを下記のように定義します。
　`neighbor(L,R,[L,R|_])`と`neighbor(L,R,[_|Xs]) :- neighbor(L,R,Xs)`
■イギリス人は赤い家に住んでいるということは：
　`house(red,english,_)`
と表します。
■スペイン人は犬を飼っているということは：
　`house(_,spanish,dog)`
とします。
■日本人は、猫を飼っている人の右側に住んでということは：
　`house(_,_,cat), house(_,japanese,_)`
とします。
■猫を飼っている人は青色の家の左に住んでいるということは：
　`(house(_,_,cat), house(blue,_,_)`
とします。

これで問題文を読み解けたので、後は上記の事実・規則を組み合わせていきます。
そしてその結果が下記です。

```lang:zebra_puzzle.swi
neighbor(L,R,[L,R|_]).
neighbor(L,R,[_|Xs]) :- neighbor(L,R,Xs).
zebra(X) :- Street = [H1,H2,H3],
            member(house(red,english,_), Street),
            member(house(_,spanish,dog), Street),
            neighbor(house(_,_,cat), house(_,japanese,_), Street),
            neighbor(house(_,_,cat), house(blue,_,_), Street),
            member(house(_,X,zebra),Street).
```
ちなみにmemberというのは「第１パラメータのデータが第２パラメータのリストに含まれているかどうか調べる関数みたいなもの」です。

これでソースコードは書けたので、Terminalから、上記のファイルが保存されているディレクトリまで行き、`swipl -f zebra_puzzle.swi`と打つとソースファイルが読み込まれます。
そして、下記のように打ち込むと・・・
`?- zebra(X).`
X = japanese 

となります！つまり、シマウマを飼っているのは、日本人であるとPrologが答えてくれました！

##最後に
Prologを久しぶりに書いて、頭の体操になりました。Prologは自然言語処理を行うのに適した言語であるので、興味がある方は是非Prologを書いて遊んでみてください！