在 SWI 中使用 SICStus 拆分原子,如 atomic_list_concat/3
Split atom using SICStus like atomic_list_concat/3 in SWI
我有一个像 'id1,id2,id3'
这样的原子,我想把它分成列表
与 SWI 中的谓词 atomic_list_concat/3 相同。
预期结果
?- atomic_list_concat(L, ',', 'id1,id2,id3').
L = [id1, id2,id3]
?- atomic_list_concat([id1,id2,id3], ',', A).
A = 'id1,id2,id3'
无论如何,是否可以使用 DCG
不考虑效率,这看起来很相似
atomic_list_concat_(L, Sep, Atom) :-
( atom(Sep), ground(L), is_list(L) )
-> list_atom(L, Sep, Atom)
; ( atom(Sep), atom(Atom) )
-> atom_list(Atom, Sep, L)
; instantiation_error(atomic_list_concat_(L, Sep, Atom))
.
list_atom([Word], _Sep, Word).
list_atom([Word|L], Sep, Atom) :-
list_atom(L, Sep, Right),
atom_concat(Sep, Right, Right1),
atom_concat(Word, Right1, Atom).
atom_list(Atom, Sep, [Word|L]) :-
sub_atom(Atom, X,N,_, Sep),
sub_atom(Atom, 0,X,_, Word),
Z is X+N,
sub_atom(Atom, Z,_,0, Rest),
!, atom_list(Rest, Sep, L).
atom_list(Atom, _Sep, [Atom]).
理由
atomic_list_concat/3 是 SWI-Prolog 中内置的便利,我认为我的代码没有完全涵盖规范(主要是因为我缺少用于测试的 SICStus Prolog)。一个值得注意的区别是可接受的 类型 的限定。对于列表元素,我坚持使用 atom 而不是 atomic 类型,因为 atom_concat/3 它是一个内置的 ISO,因此应该禁止 SWI-Prolog 实现接受的一些模式。
关于代码,当类型测试确定转换方向时,实现很简单:我在 list_atom/3 中选择了一个简单的递归连接,可以很容易地优化,例如添加一个累加器并因此使其尾递归优化,同时 atom_list/3 从左到右扫描寻找分隔符,当它找到它时,存储在列表头中并获取递归的正确部分。
关于一个头脑简单的 DCG 实现,我使用这段代码来测试由 dcg_util 实现的一个很好的抽象列表//3,导致这个紧凑的代码:
list_atom(L, Sep, Atom) :-
phrase(list(atom_codes, atom_codes(Sep), L), AtomCs),
atom_codes(Atom, AtomCs).
atom_codes(A) --> {atom_codes(A, Cs)}, Cs.
atom_list(Atom, Sep, L) :-
atom_codes(Atom, AtomCs),
phrase(list(any, atom_codes(Sep), LCs), AtomCs),
!, maplist(atom_codes, L, LCs).
any([]) --> [].
any([C|Cs]) --> [C], any(Cs).
不用list直接实现就够简单了//3...
我知道这不是完美的答案,但我做了一些努力,因为我的目标是学得更好,
代码
% NOTE 'Separator' must be a single character
% atomic_list_concat(Atom,Separator,List)
% test => L='id1,id2,id3' , atomic_list_concat(L,',',Ls).
atomic_list_concat(Atom,Separator,Res) :- atom_chars(Atom,CAtom),
atomic_list_concat_(CAtom,Separator,List),
maplist(atom_chars,Res,List).
% test => L='id1,id2,id3',atom_chars(L,CL) , atomic_list_concat_(CL,',',Ls).
atomic_list_concat_([],_,[[]]) :- ! .
atomic_list_concat_([A|As],Sep,[[]|Args]) :- A=Sep,
atomic_list_concat_(As,Sep,Args).
atomic_list_concat_([A|As],Sep,[[A|Arg]|Args]) :- A\=Sep,
atomic_list_concat_(As,Sep,[Arg|Args]).
测试
| ?- L='id1,id2,id3' , atomic_list_concat(L,',',Ls).
L = 'id1,id2,id3',
Ls = [id1,id2,id3] ? ;
no
我有一个像 'id1,id2,id3'
这样的原子,我想把它分成列表
与 SWI 中的谓词 atomic_list_concat/3 相同。
预期结果
?- atomic_list_concat(L, ',', 'id1,id2,id3').
L = [id1, id2,id3]
?- atomic_list_concat([id1,id2,id3], ',', A).
A = 'id1,id2,id3'
无论如何,是否可以使用 DCG
不考虑效率,这看起来很相似
atomic_list_concat_(L, Sep, Atom) :-
( atom(Sep), ground(L), is_list(L) )
-> list_atom(L, Sep, Atom)
; ( atom(Sep), atom(Atom) )
-> atom_list(Atom, Sep, L)
; instantiation_error(atomic_list_concat_(L, Sep, Atom))
.
list_atom([Word], _Sep, Word).
list_atom([Word|L], Sep, Atom) :-
list_atom(L, Sep, Right),
atom_concat(Sep, Right, Right1),
atom_concat(Word, Right1, Atom).
atom_list(Atom, Sep, [Word|L]) :-
sub_atom(Atom, X,N,_, Sep),
sub_atom(Atom, 0,X,_, Word),
Z is X+N,
sub_atom(Atom, Z,_,0, Rest),
!, atom_list(Rest, Sep, L).
atom_list(Atom, _Sep, [Atom]).
理由
atomic_list_concat/3 是 SWI-Prolog 中内置的便利,我认为我的代码没有完全涵盖规范(主要是因为我缺少用于测试的 SICStus Prolog)。一个值得注意的区别是可接受的 类型 的限定。对于列表元素,我坚持使用 atom 而不是 atomic 类型,因为 atom_concat/3 它是一个内置的 ISO,因此应该禁止 SWI-Prolog 实现接受的一些模式。
关于代码,当类型测试确定转换方向时,实现很简单:我在 list_atom/3 中选择了一个简单的递归连接,可以很容易地优化,例如添加一个累加器并因此使其尾递归优化,同时 atom_list/3 从左到右扫描寻找分隔符,当它找到它时,存储在列表头中并获取递归的正确部分。
关于一个头脑简单的 DCG 实现,我使用这段代码来测试由 dcg_util 实现的一个很好的抽象列表//3,导致这个紧凑的代码:
list_atom(L, Sep, Atom) :-
phrase(list(atom_codes, atom_codes(Sep), L), AtomCs),
atom_codes(Atom, AtomCs).
atom_codes(A) --> {atom_codes(A, Cs)}, Cs.
atom_list(Atom, Sep, L) :-
atom_codes(Atom, AtomCs),
phrase(list(any, atom_codes(Sep), LCs), AtomCs),
!, maplist(atom_codes, L, LCs).
any([]) --> [].
any([C|Cs]) --> [C], any(Cs).
不用list直接实现就够简单了//3...
我知道这不是完美的答案,但我做了一些努力,因为我的目标是学得更好,
代码
% NOTE 'Separator' must be a single character
% atomic_list_concat(Atom,Separator,List)
% test => L='id1,id2,id3' , atomic_list_concat(L,',',Ls).
atomic_list_concat(Atom,Separator,Res) :- atom_chars(Atom,CAtom),
atomic_list_concat_(CAtom,Separator,List),
maplist(atom_chars,Res,List).
% test => L='id1,id2,id3',atom_chars(L,CL) , atomic_list_concat_(CL,',',Ls).
atomic_list_concat_([],_,[[]]) :- ! .
atomic_list_concat_([A|As],Sep,[[]|Args]) :- A=Sep,
atomic_list_concat_(As,Sep,Args).
atomic_list_concat_([A|As],Sep,[[A|Arg]|Args]) :- A\=Sep,
atomic_list_concat_(As,Sep,[Arg|Args]).
测试
| ?- L='id1,id2,id3' , atomic_list_concat(L,',',Ls).
L = 'id1,id2,id3',
Ls = [id1,id2,id3] ? ;
no