Prolog 写経記 その 14 insert_n/4

(ほぼ) 毎日淡々と Prolog を写経します.元ネタはこちら.

Prologユーティリティライブラリ

Prologユーティリティライブラリ

今日は insert_n/4 を写経します.

解説

insert_n(N, X, List1, List2) は要素 XList1N 番目の位置に挿入した新しいリストを List2 として返す.

ふむ.Java でいうと List#add(int, Object) みたいな.

モード

insert_n(?, ?, ?, ?)

ふむ.まぁ例によって.

定義

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

insert_n(N, X, List1, List2) :-
	conc(L1, L2, List1),
	length(L1, L),
	N is L + 1,
	conc(L1, [X|L2], List2).

基本的な発想はいつも通りですね.
リストを X とその左の要素からなるリスト (L1),右の要素からなるリスト (L2) に分けて,

  • L1L2 を連結したリストが List1
  • L1XL2 を連結したリストが List2

ということですね.
その上で,L1 の長さは N - 1 ってことを示すのが

	length(L1, L),
	N is L + 1,

の部分.
こういうのはやっぱりこうなるんですね.ってことなら,フィジカルネタでおいらがやったこともそんなに手続き的というわけでもないのだろうか?

注記

以下の例は insert_n がそれぞれ初期設定された引数の違いによってどのように適用できるかを示している.バックトラック時に無限ループに陥るのを避けるため,List1 は少なくとも部分的に具体化されている必要がある.

例によって無限ループの危険性がある,と.らじゃあ.

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

2 ?- insert_n(3, 4/5, [1/2, 2/3, 4/4], L).

L = [1/2, 2/3, 4/5, 4/4] ;

No
3 ?- insert_n(N, b, [_, _, _], [a, b, c, d]).

N = 2 ;

No
4 ?- insert_n(P, X, [4, 6], [2, 4, 6]).

P = 1
X = 2 ;

No

2 番目の例が List1 を「部分的に具体化」した例ですね.
これを全く具体化せずに呼び出してみると...

5 ?- insert_n(N, b, L, [a, b, c, d]).

N = 2
L = [a, c, d] ;

...
別の解を求めるためのセミコロンを入力した後,きっちり無限ループになって返ってきません.(^^;