Split atom using SICStus like atomic_list_concat/3 in SWI

随声附和 提交于 2019-12-11 10:14:39

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!