ルールを両方向に使う on 7つの言語7つの世界

append(List1, List2, List3)は、List3がList1 + List2のとき真になるらしい。

1 ?- append([oil], [water], [oil, water]).
true.
真偽を確かめる1

2 ?- append([oil], [water], [oil, slick]).
false.
真偽を確かめる2

3 ?- append([tiny], [bubbles], What).
What = [tiny, bubbles].
リストを新規で作成する。

4 ?- append([topping], What, [topping, banana]).
What = [banana].
リストの差分を取る。

5 ?- append(One, Two, [a, b, c]).
One = ,
Two = [a, b, c] ;
One = [a],
Two = [b, c] ;
One = [a, b],
Two = [c] ;
One = [a, b, c],
Two =
;
false.
リストを分割する際のパターンを洗い出す。
これスゲーなマジで!
1つのルールで4つのことが出来てしまうことになるらしい。

これを自前で定義すると以下のようになるそうな

concatenate([], List, List).
concatenate([Head|Tail1], List, [Head|Tail2]) :- 
  concatenate(Tail1, List, Tail2). 

concatenate([1, 2], [3], What).
Whatには、[1, 2, 3]が入ることを期待する。

1番目のルールにはマッチしないので2番目のルールに当てはめる
concatenate([1 | [2]], [3], [1 |Tail2-A]) :-
concatenate([2], [3], Tail2-A).
Tail2-Aが不明なので、さらにルールを適用(2番目のルール)
concatenate([2 | ], [3], [2 | Tail2-B]) :-
concatenate(
, [3], Tail2-B).
Tail2-Bが不明なので、さらにルールを適用(1番目のルール)
concatenate([], [3], [3]).
これでTail2-Bが[3]であることがわかる。
Whatは[1 | 2 | [3]]なので、[1 | [2, 3]]となり、[1, 2, 3]となる。

たった3行で、これすごいけど、相当頭良くないとソラで書けないと思う。
そーゆー意味では、GeneXusっていうウルグアイ生まれのフレームワーク(?)は
業務要件を入力するとJavaやCのソースを自動生成してくれるんだけど
その内部では、Prologが使われているわけで、どんだけすごいコード書いとんねん!
ってことになる。

1 ?- listing.

concatenate([], A, A).
concatenate([A|B], C, [A|D]) :-
        concatenate(B, C, D).
true.

2 ?- concatenate([oil], [water], [oil, water]).
true.

3 ?- concatenate([oil], [water], [oil, slick]).
false.

4 ?- concatenate([tiny], [bubbles], What).
What = [tiny, bubbles].

5 ?- concatenate(One, Two, [a, b, c]).
One = [],
Two = [a, b, c] ;
One = [a],
Two = [b, c] ;
One = [a, b],
Two = [c] ;
One = [a, b, c],
Two = [] ;
false.

結果は、標準の(?)appendと同じ動作をする。