问题
i have an atom like 'id1,id2,id3'
and i want to split it into list
with same way as the predicate atomic_list_concat/3 in SWI .
expected result
?- atomic_list_concat(L, ',', 'id1,id2,id3').
L = [id1, id2,id3]
?- atomic_list_concat([id1,id2,id3], ',', A).
A = 'id1,id2,id3'
anyway, is it possible to do it using DCG
回答1:
without any regard to efficiency, this seems fairly similar
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]).
rationale
atomic_list_concat/3 is a convenience built-in in SWI-Prolog, I think my code doesn't cover fully the specification (mainly because I lack SICStus Prolog for testing). A noteworthy difference is the qualification of acceptable types. I'm sticking to atom instead of atomic types for list' elements, because atom_concat/3 it's an ISO built-in, as such should ban some patterns accepted by SWI-Prolog implementation.
About the code, when the type testing has decided about the direction of conversion, the implementation is simple: I opted for a simple recursive concatenation in list_atom/3, that could be easily optimized, for instance adding an accumulator and thus making it tail recursion optimized, while atom_list/3 scan left to right looking for separator, and when it find it, store in list head and get the right part for recursion.
About a simple minded DCG implementation, I used this code to test a nice abstraction list//3 implemented by dcg_util, leading to this compact code:
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).
Would be simple enough to directly implement without list//3...
回答2:
I Know that is not the perfect answer, but I do some effors because my goal is to learn better,
Code
% 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]).
test
| ?- L='id1,id2,id3' , atomic_list_concat(L,',',Ls).
L = 'id1,id2,id3',
Ls = [id1,id2,id3] ? ;
no
来源:https://stackoverflow.com/questions/35317539/split-atom-using-sicstus-like-atomic-list-concat-3-in-swi