Prolog 写経記 その 9 list/1

今日は list/1 を写経します.
本来の順番だと flatten/2 になるのですが,その中で list/1 が使われているのでこちらを先に.

解説

list(X)X がリストかどうかを調べる.

ふむ.型付けが弱いうえにポリモーフィズムがあるのかどうか怪しげな Prolog だけに,こういうのが必要になりそうですよね.

モード

list(?).

入出力どっちでも使えます.なぜ?
未定義の変数を与えると何が返ってくるのだろうか?

定義

では,こいつの定義を写経しませう.

list([]).
list([_|_]).

簡単といえば簡単ですが,見た瞬間はちょっと違和感を覚えました.
二つの節を使わないと,リストかどうか判断できないんですね.

2 ?- [_] = [].

No
3 ?- [_|_] = [].

No
3 ?- [_] = [a].

Yes
4 ?- [_|_] = [a].

Yes
5 ?- [_] = [a, b].

No
6 ?- [_|_] = [a, b].

Yes

そうですか,空リストにマッチするのは空リストだけなのね.

注記

list によるデータタイプの検査にはいくつかの注意が必要である.変数 X が具体化されていなければ,list(X) が最初に呼ばれた時には空リスト [] に,またバックトラックの時は [_|_] に具体化される.list が述語 flatten/2 の定義中でどのように用いられているかを参照のこと.

うーみゅ...
悩ましすぎる.ちょっと意味不明.あとでお試ししませう.

では使用例を写経しませう.

7 ?- list(a).

No
8 ?- list([]).

Yes
9 ?- list([a, b, c, d]).

Yes
10 ?- list([x|_]).

Yes
11 ?- list([_, z|[]]).

Yes
12 ?- list([]).

Yes
13 ?- list(list).

No

まぁいいでしょう.普通に使えてるっぽい.


そんなわけで (どんなわけで?),注記の記述を確認してみます.

14 ?- list(X).

X =  ;

X = [_G290|_G291] ;

X =  ;

X = [_G290|_G291] ;

No

な,なんだこりゃあ!!
確かに注記に書いてあるように,具体化されていない変数 X は最初空リストとしてマッチしちゃってますね.
そして再試行すると [_|_] に訳の分からないリストがマッチしちゃってます.
それがなぜか 2 回ずつ.なぜ 2 回? なぜ 1 回でも 3 回でもなく 2 回?
うーみゅ...
そんなわけで (どんなわけで?),flatten/2 の定義を参照...
するのは明日のお楽しみってことで.心より恥じる.