Prolog 写経記 その 70 write_list_continued/2

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

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

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

今日は write_list_continued/2 を写経します.

解説

write_list_continued(List, N)List の要素を現在の出力ストリームに書き出す.この述語は 1 行に可能なだけ(80 文字)の要素を出力し,各要素はコンマによって仕切られ,行は N このスペースによって字下げされる.

ふむ.

モード

write_list_continued(+, +).

ふむ.

定義

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

write_list_continued([], _).
write_list_continued([X | List], N) :-
	nl,
	tab(N),
	write(X),
	count_chars([X], Chars),
	count_first(List, Chars0),
	Chars1 is N + Chars + 2 + Chars0, !,
	write_rest(List, N, Chars1).

write_rest([], _, _) :- !.
write_rest(List, N, Chars) :-
	Chars > 78,
	write(', '), !,
	write_list_continued(List, N).
write_rest([X | List], N, Chars) :-
	write(', '),
	write(X),
	count_first(List, Chars0),
	Chars1 is Chars + Chars0 + 2, !,
	write_rest(List, N, Chars1).

count_first([], 0).
count_first([X | _], Chars) :-
	count_chars([X], Chars).

count_chars([], 0).
count_chars([Var | List], N) :-
	var(Var), !,
	count_chars(List, N0),
	N is N0 + 5.
count_chars([Atom | List], N) :-
	atomic(Atom), !,
	name(Atom, ASCII),
	length(ASCII, N0),
	count_chars(List, N1),
	N is N0 + N1.
count_chars([Term | List], N) :-
	Term =.. L,
	count_chars(L, N0),
	count_chars(List, N1),
	N is N0 + N1.

ぬおぉーーーーーっ!?
なんちゅー長さじゃ.写経本史上最長ですな...
一つずつ見ていきますか.


まずは本体.

write_list_continued([], _).
write_list_continued([X | List], N) :-
	nl,
	tab(N),
	write(X),
	count_chars([X], Chars),
	count_first(List, Chars0),
	Chars1 is N + Chars + 2 + Chars0, !,
	write_rest(List, N, Chars1).

最初の節は停止条件
2 番目の節が本当の本体で,改行して,N 文字分タブを出力して,リストの先頭の要素を出力します.
そして count_chars/2 で出力したリストの先頭の要素の長さ (Chars) を求め,count_first/2 でリストの2番目の要素 (List の先頭の要素) の長さ (Chars0) を求めます.
出力した文字の数 (タブ幅 + リストの先頭の要素の長さ) とこれから出力する文字の数 (区切り文字の幅 + リストの 2 番目の要素の長さ) の合計を求めます.
最後に write_rest/3 でリストの残りの要素を出力します.
ふむ.


次に write_rest/3

write_rest([], _, _) :- !.
write_rest(List, N, Chars) :-
	Chars > 78,
	write(','), !,
	write_list_continued(List, N).
write_rest([X | List], N, Chars) :-
	write(','),
	write(X),
	count_first(List, Chars0),
	Chars1 is Chars + Chars0 + 2, !,
	write_rest(List, N, Chars1).

最初の節は停止条件
2 番目の節は... 第 3 引数 Chars はタブ幅 + 直前に出力した要素の長さ + 次に出力する要素の長さ.
それが 78 を超えている場合は新たな行として次の要素を出力するため,区切り文字を出力した後 write_list_continued を呼び出します.
3 番目の節は現在の行に次の要素を出力できる場合.
なので,区切り文字を出力して,リストの先頭の要素を出力します.
count_list_continued/2 の最後の節と同様に,次の要素を出力した場合の文字数を計算して write_rest/3 を呼び出します.
ふむふむ.


次.

count_first([], 0).
count_first([X | _], Chars) :-
	count_chars([X], Chars).

ふむふむふむ.


最後.

count_chars([], 0).
count_chars([Var | List], N) :-
	var(Var), !,
	count_chars(List, N0),
	N is N0 + 5.
count_chars([Atom | List], N) :-
	atomic(Atom), !,
	name(Atom, ASCII),
	length(ASCII, N0),
	count_chars(List, N1),
	N is N0 + N1.
count_chars([Term | List], N) :-
	Term =.. L,
	count_chars(L, N0),
	count_chars(List, N1),
	N is N0 + N1.

なかなか微妙.
リストが空だったら長さ 0.当然.
リストの先頭の要素が具体化されていない変数だったら,リストの残りの長さ + 5.適当気味.
リストの先頭の要素がアトムだったら文字のリストにしてその長さ + リストの残りの長さ.
リストの先頭の要素が項だったらリストに変換してその長さ + リストの残りの長さ.
ふむふむふむ

注記

count_chars(X, N) はデータ対象 X の名前中の文字数を返す.具体化されていない変数は通常,_0905 のように先頭に下線をつけた数字の並びとして,出力ストリームに書き出される.編集表示の長さは種々の Prolog の版でわずかに異なるため,count_chars の 2 番目の節中の定数は調整する必要がある.

ふむ.
SWI-Prolog の場合,変数は _G218 みたいに表示されるので,このままで構いませんね.

では使用例を写経しませう.
...
と思ったのに例がない.(;_;)
しょうがないので自前で.

5 ?- write_list_continued([aaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbb, ccccccccccccccccccccccccc, ddddddddddddddddddddddddddd, eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee, ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, G, [hhhhhhhhhhhhhhhhhhhh, iiiiiiiiiiiiiiiiiiiiiii, jjjjjjjjjjjjjjjjjjjjjjjj], kkkk(llllllllllllllllllllll, mmmmmmmmmmmmmmmmmmmmmm, nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn), , pppppppppppppppppppppppppppppppppppppppppppppppppppppppp], 5).

     aaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbb, ccccccccccccccccccccccccc, 
     ddddddddddddddddddddddddddd, 
     eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee, 
     ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 
     _G3434, 
     [hhhhhhhhhhhhhhhhhhhh, iiiiiiiiiiiiiiiiiiiiiii, jjjjjjjjjjjjjjjjjjjjjjjj], 
     kkkk(llllllllllllllllllllll, mmmmmmmmmmmmmmmmmmmmmm, nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn), 
     , pppppppppppppppppppppppppppppppppppppppppppppppppppppppp

G = _G3434 

Yes

ほほー.
うまく動いているらしい.
でもでも,長々と打ち込んだ割にはつまらない感じ.
だってだって,普通に手続きチックなんだもん.