Prolog 写経記 その 19 list_to_atom/2

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

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

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

lengths の次は list/2 です.
でもでも,なんだか見覚えが...
おぉ!!
やはり「その 9」で写経済みでしたよ.危ない危ない.
そんなわけで (どんなわけで?),今日は list_to_atom/2 を写経します.

解説

list_to_atom(Atoms, Name) はアトムのリスト Atom からアトム Name を作り出す.

うーみゅ,一瞬意味が分かりませんでしたが...
つまり,[a, b, c] というリストから abc というアトムを作ってくれる訳ね.ふーん.

モード

lsit_to_atom(+, ?)

ふむ.

定義

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

list_to_atom(Atoms, Name) :-
	ascii(Atoms, List),
	name(Name, List).
ascii([Atom], List) :-
	!,
	name(Atom, List).
ascii([Atom | Atoms], List) :-
	name(Atom, L),
	conc(L, Rest, List), !, 
	ascii(Atoms, Rest).

お,下請け君がいますね.
3度も使われている述語 name/2 は組み込み述語.なんでも,第1引数で受け取ったアトムを文字にばらしてそのリストを第2引数に具体化してくれたりその逆をしてくれたりするらしい.

2 ?- name(a, L).

L = [97] 

Yes
3 ?- name(abc, L).

L = [97, 98, 99] 

Yes

ふむ.


んで,下請け述語 ascii/2 の最初の節

ascii([Atom], List) :-
	!,
	name(Atom, List).

これは再帰の終了条件で,第 1 引数のリストに要素 (アトム) が一つしかなければ,name/2 でそのアトムをリストにします.
そしてもう一つの節.

ascii([Atom | Atoms], List) :-
	name(Atom, L),
	conc(L, Rest, List), !, 
	ascii(Atoms, Rest).

ふむ.
第 1 引数で渡されたリストの最初の要素 (アトム) をリストにしたものと,残りの要素 (アトム) からなるリストを文字のリストにしたものを連結しています.


そして本体.

list_to_atom(Atoms, Name) :-
	ascii(Atoms, List),
	name(Name, List).

第 1 引数で渡されたアトムのリストをフラットな文字のリストにして,name/2 でそれをアトムにする,と.
ふむ.本体と下請けでは,同じ name/2 を使っているものの使い方の向きが逆なんですね.

注記

もしリスト Atoms の要素が Prolog のアトムでない時 list_to_atom は失敗する.

ふむふむ.

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

4 ?- list_to_atom([john, ate, three, eggs, for, breakfast], A).

A = johnatethreeeggsforbreakfast 

Yes
5 ?- list_to_atom([a, 1], a1).

Yes
6 ?- list_to_atom([colour(blue), colour(red)], X).
ERROR: name/2: Type error: `atom' expected, found `colour(blue)'

失敗って...
冷たく「No」って返ってくるんじゃなくて,こういう失敗ですか.
っていうか,写経本の例だと「No」って返ってくるだけになってるなぁ.
この辺りは処理系によって違うということでしょうか.


ところで,この list_to_atom/2 はリストの連結に conc/2 を使っています.
そんなわけで (どんなわけで?),これを差分リストを使うように直してみませう.
...
と思ったのですが,name/2 が普通のリストを返してくるから,どうやってもこいつを差分リストとして扱うためには要素数分たどるしかないような気のせいが.うーみゅ...
なんか,効率的になりそうな気がしないのでやめ.心より恥じる.