語とカテゴリのリストから、語だけ取り出すprologのルール

前の記事で、語とカテゴリのリストのことを書いたが、このリストから語だけを全て取り出すprologのルールをほぼ1日かけて作成した。単純なはずなのだが、なかなかうまくいかなかった。また、prologというものに、完全に馴染んでいないからだと思う。普通のc, java, pythonなどと、プログラムの考え方が、全く異なっているのだから。

ルールは、次のようになる。 %で、始まる行はコメントである。

%% headがアトムの場合、tailから取り出したものと結合する
%% 特殊な二分木なので、tailに複雑に構造化されたリストはあり得ない
%% atomか[a,b]の形のものしか、tailの要素にはならないのだ
getlist([H|[T]],[H,H1]) :- atom(H),[H1|_] = T,!.
%% headがatomならば、それを取り出す
getlist([H|[_]],H) :- atom(H),!.
%% tailがatomの場合:その場合でも、headからは、必ず1個以上のatomが該当する
getlist([H|[T]],[Z,T]) :- atom(T),getlist(H,Z),!.
%% 残されたのは、headもtailもリストの場合
getlist([H|[T]],[X1, X2]) :- getlist(H,X1),getlist(T,X2).

これをswi-prologで。いくつかの場合に適応してみた例が以下のものである。

1 ?- [user]. 
|: getlist([H|[T]],[H,H1]) :- atom(H),[H1|_] = T,!.
|: getlist([H|[_]],H) :- atom(H),!.
|: getlist([H|[T]],[Z,T]) :- atom(T),getlist(H,Z),!.
|: getlist([H|[T]],[X1, X2]) :- getlist(H,X1),getlist(T,X2).
|: ^D
% user://1 compiled 0.00 sec, 4 clauses
true.

2 ?- getlist([a,b],X).
X = a.

3 ?- getlist([a,[b,c]],X).
X = [a, b].

4 ?- getlist([[[a,b],[c,d]],[e,f]],X). 
X = [[a, c], e].

5 ?- getlist([[a,b],[c,d]],X).
X = [a, c].

6 ?- getlist([[a,b],c],X).
X = [a, c].

7 ?- getlist([[[下, '場所-機能'], [人, 人]],[菓子, '人工物-食べ物']],X).
X = [[下, 人], 菓子].

8 ?- 

最初は、ルールを[user].で読み込ませているところで、2 以降が実行結果である。4でリストが二重になっているところが気になる他は、きちんと頭を取り出して、リストにしている。7は、前の記事での例を実行させたもので、カテゴリを除く語だけ取り出していることが理解できるだろう。

ただし、すべての場合を尽くしていないので、不都合が現れるかもしれない。