Пролог - Как отделить атомы от выражения с участием предикатов? - PullRequest
0 голосов
/ 06 февраля 2019

Если у меня есть выражение:

x + y * (-z)

Как разделить их, чтобы сформировать список из [x,y,z]?

Моя идея:

split2(X, [X]) :-
    X \= +(_,_),
   *(_,_),
   -(_).

split2(X + Y, [H|T]) :- 
    split2(X,[H]), 
    split2(Y, T).

(Повторите для * и -).

Каким-то образом это работает только для простого случая (включающего 2 термина или только один предикат), но не сложного.

Может кто-нибудь сказать мне, что не так смоя идея?

Ответы [ 3 ]

0 голосов
/ 07 февраля 2019

Может кто-нибудь сказать мне, что не так с моей идеей?

То, что вы делаете, слишком сложно, вот что не так.Если в качестве входных данных у вас действительно есть действительный составной термин, и вам нужно получить из него список атомарных подтерминов, то вот что вы можете попробовать:

expression_atoms(E) -->
    {   compound(E),
        E =.. [_Name|Args]
    },
    !,
    expression_list_atoms(Args).
expression_atoms(E) -->
    {   atomic(E)
    },
    !,
    [E].

expression_list_atoms([E|Es]) -->
    expression_atoms(E),
    expression_list_atoms(Es).
expression_list_atoms([]) --> [].

(Редактирование ниндзя: см. Решение Пауло Моуры для более четкой реализации той же идеи.)

Единственная причина, почему это DCG, а не обычный предикат, заключается в том, что я слишкомлень выяснить, как правильно выполнить сложение.

Вот небольшой тест:

?- X = x + y * (-z).
X = x+y* -z.

?- X = x + y * (-z), write_canonical(X).
+(x,*(y,-(z)))
X = x+y* -z.

?- X = x + y * (-z), write_canonical(X), phrase(expression_atoms(X), Atoms).
+(x,*(y,-(z)))
X = x+y* -z,
Atoms = [x, y, z].

В последнем запросе вы можете увидеть атомы, извлеченные из выражения.

Как видите, это решение не заботится об именах составных терминов.Это происходит в строке 3 списка:

E =.. [_Name|Args]

Таким образом, вы можете бросить в него что угодно, и оно все равно будет «работать»:

?- phrase(expression_atoms(
    the(naked, truth(about(our(waitresses))), is(that(they(only(flirt, with, you))), to(get(a(better(tip('!')))))))),
    Atoms).
Atoms = [naked, waitresses, flirt, with, you, !].

Если вы хотите, чтобы это ни к чему не привелоиначе, кроме предопределенного списка операторов с заданной арностью, вам придется добавить туда немного больше кода.

0 голосов
/ 07 февраля 2019

Следует решению, использующему DCG, в котором не требуется грамматическое правило для каждого арифметического оператора и которое полностью использует индексирование первого аргумента (таким образом, избегая ложных точек выбора или безобразных сокращений в правилах грамматики):

split(Expression, Atomics) :-
    Expression =.. [Functor| Args],
    phrase(split_atomics(Args, Functor), Atomics).

split_atomics([], Atomic) -->
    [Atomic].
split_atomics([Head| Tail], _) -->
    split_list([Head| Tail]).

split_list([]) -->
    [].
split_list([Head| Tail]) -->
    {Head =.. [Functor| Args]},
    split_atomics(Args, Functor),
    split_list(Tail).

Примеры звонков:

| ?- split((x + y * (-z)), Atomics).

Atomics = [x, y, z]
yes

| ?- split((x + 3 * (-2)), Atomics).

Atomics = [x, 3, -2]
yes
0 голосов
/ 06 февраля 2019

Ваши предикаты довольно запутаны.Для начала вы используете X \= _+_, чтобы предотвратить сопоставление другого правила;вместо этого вы должны использовать atomic(X).Вы тогда говорите _*_, -_, что не говорит явно ничего конкретного, кроме того, что существуют определенные анонимные переменные ... существуют?В любом случае, остальная часть первого предложения ошибочна по той или иной причине.

Ваше второе предложение положено неплохо, но я думаю, что вы избегаете использования append/3 здесь без особой причины.В голове вы ожидаете, что H будет атомом, но затем с первым членом в теле вы заставляете H быть одноэлементным списком.Что если X = a*b?Вы ожидаете, что split2(a*b,[a,b]) объединится.

Хотя вы не далеко от того места, где вам нужно быть.Вероятно, это ваш общий шаблон:

split2(X, [X]) :- atomic(X).
split2(-X, Result) :- split2(X, Result).
split2(X+Y, Result) :-
    split2(X, XVars),
    split2(Y, YVars),
    append(XVars, YVars, Result).

Продолжите шаблон для других ваших операторов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...