Prolog

【Prolog】「法律家のためのコンピュータ利用法」より”システム述語を全て表示するプログラム”をGNU Prologで

【Prolog】「法律家のためのコンピュータ利用法」より”システム述語を全て表示するプログラム”をGNU Prologで

「法律家のためのコンピュータ利用法」
http://www.yuhikaku.co.jp/books/detail/4641075417
タイトルからは想像し難いPrologの本、既に絶版のため古書を購入しました。
実務を前提とした具体的な実例と、例題1つ1つに「この問題を通して何を会得して欲しいのか」の記載があり大変理解しやすいです。
(フロッピーディスクのフォーマット方法からPrologの歴史まで分かりやすい)

一方で、古い書籍ということと、書籍内で使われている処理系が現在の標準と異なるため、SWI-Prolog等今のメジャーな処理系では記載例は動作しません。
ここでは本書記載の例題を、手元の処理系GNU Prologで解いてみます。

※実行環境:GNU Prolog 1.4.4

システム述語を全て表示するプログラム

下記のような練習問題が記載されています。

Prologのシステム述語かどうか調べることができるsystem/1を使って
~中略~
全てのシステム述語を表示するプログラムsys_all/0を書きなさい

しかし、今のISO標準にはsystem述語は無いようです。
(なおGNU Prologではsystem/1は別の目的の述語として定義されていました。http://www.gprolog.org/manual/gprolog.html#hevea_default880

current_predicate

組み込み述語のドキュメントを見ると、述語を表示する述語はcurrent_predicate/1のようです。
http://www.gprolog.org/manual/gprolog.html#hevea_default296

current_predicate(Pred) succeeds if there exists a predicate indicator of a defined procedure that unifies with Pred.

なるほど。

| ?- current_predicate(current_predicate/1).
no

| ?- current_predicate(Pred).
no

・・・。

set_prolog_flag(strict_iso, off)

しばらく横になったところ、きちんとドキュメントに書いてありました。

http://www.gprolog.org/manual/gprolog.html#hevea_default296

To conform to the ISO reference, built-in predicates are not found except if the strict_iso Prolog flag is switched off (section 8.22.1)

strict_isoというシステムフラグをOFFにしないと、組み込み述語は表示されないようです。

| ?- set_prolog_flag(strict_iso, off).
yes

| ?- current_predicate(current_predicate/1).
yes

| ?- current_predicate(Pred).
Pred = max_list/2 ? 
...

| ?- current_predicate(F/A).
A = 2
F = max_list ? 
...

あとはcurrent_predicateをバックトラックさせ続ければOKですね

current_predicate_all.pro
:- set_prolog_flag(strict_iso, off).

current_predicate_all :- current_predicate(F/_), write(F), nl, fail.
current_predicate_all.
| ?- current_predicate_all.
max_list
at_end_of_stream
...
get_byte
syntax_error_info
(547 ms) yes

システム述語の検索プログラム

これに続いて、

部分文字列から、システム述語を表示するプログラムfind_sys/1を書きなさい。

という例題が登場し、string_search/3という文字列検索述語、change_to_string/2というatomを文字列に変換する述語をそれぞれ使うよう指示がありますが、いずれもGNU Prologにはありません。

sublist, name

Prologでは文字列=配列なので、

| ?- write("name").
[110,97,109,101]
yes

リスト1がリスト2の部分配列であることを証明するだけで良さそうです。
ということで組み込み述語sublistを使います。
http://www.gprolog.org/manual/gprolog.html#hevea_default704

また、後者はname/2という組み込み述語がありました。
http://www.gprolog.org/manual/gprolog.html#hevea_default679

ということで、これらを利用し、find_predicate/1を定義します。

find_predicate.pro
find_predicate(Str) :- current_predicate(F/A), name(F, FName), sublist(Str, FName), write(F/A), nl, fail.
find_predicate(_).
| ?- find_predicate("name").
temporary_name/2
decompose_file_name/4
...
current_bip_name/2
(16 ms) yes

終わり

無事例題の目的を達成できました。
・・・と思ったのですが、「述語名の一部を入力して、部分一致する述語名を出力する」なら文字列にする必要がありませんでした。

sub_atom

sub_atomを使えばOKですね。
http://www.gprolog.org/manual/gprolog.html#hevea_default671

find_predicate.pro
find_predicate(Atom) :- current_predicate(F/A), sub_atom(F, _, _, _, Atom), write(F/A), nl, fail.
find_predicate(_).

書籍内ではこの問題の後に、条文等の文章やそのデータベースを扱う例題があるため、その取っ掛かりとして文字列を扱う形での問題としたようです。