Ваша интуиция верна; процедура расширения термина для DCG (по крайней мере, в SWI-Prolog, но должна применяться к другим) с вашей измененной версией data
дает следующее:
?- listing(data).
data(A, D, B, F) :-
phrase(A, B, C),
spaces(_, C, E),
phrase(D, E, F).
Как видите, переменные Part1
и Part2
части вашего правила DCG были снова интерпретированы как вызовы phrase/3
, а не списки; вам нужно явно указать, что они являются списками для них, которые будут рассматриваться как таковые.
Я могу предложить альтернативную версию, которая является более общей. Рассмотрим следующую группу правил DCG:
data([A|As]) -->
spaces(_),
chars([X|Xs]),
{atom_codes(A, [X|Xs])},
spaces(_),
data(As).
data([]) --> [].
chars([X|Xs]) --> char(X), !, chars(Xs).
chars([]) --> [].
spaces([X|Xs]) --> space(X), !, spaces(Xs).
spaces([]) --> [].
space(X) --> [X], {code_type(X, space)}.
char(X) --> [X], {\+ code_type(X, space)}.
Взгляните на первый пункт сверху; Правило data
теперь пытается сопоставить пробелы от 0 до многих (как можно больше из-за разреза), а затем от одного до многих непробельных символов для построения атома (A
) из кодов, затем снова пробелы 0-ко-многим, затем рекурсивно, чтобы найти больше атомов в строке (As
). В итоге вы получите список атомов, которые появились во входной строке без пробелов. Вы можете включить эту версию в свой код следующим образом:
processData(Codes) :-
% convert the list of codes to a list of code lists of words
(phrase(data(AtomList), Codes) ->
% concatenate the atoms into a single one delimited by commas
concat_atom(AtomList, ', ', Atoms),
write_ln(Atoms)
;
format('Didn''t recognize data.\n')
).
Эта версия разбивает строку на любое количество пробелов между словами, даже если они появляются в начале и конце строки.