Вызов фразы/2 в списке правил грамматики, а не в списке атомов

С такой грамматикой:

as --> [].
as --> [a], as.
b(b(a)) --> as.
c(X) --> b(X).

phrase(b(X), [a, a]) и phrase(c(X), [a, a]) работают без проблем. Оба возвращают X = b(a)..

Но можно ли унифицировать что-то подобное?

phrase(c(X), [b(a)]).
OR:
phrase(c(X), [b(b(a))]).

Мне не повезло, хотя кажется, что это должно быть возможно. Я думаю, это означает, что у меня есть некоторое недопонимание о DCG. Я знаю, что они работают со списками различий и добиваются успеха, когда могут применить ряд правил для использования всех элементов списка. Есть ли что-то особенное в атомах или токенах с точки зрения phrase/2?

Вот как выглядит трассировка:

[trace] [4]  ?- phrase(c(X), [b(a)]).
   Call: (5,411) c(_57162, [b(a)], []) ? creep
   Call: (5,412) b(_57162, [b(a)], []) ? creep
   Call: (5,413) [b(a)]as[] ? creep
   Fail: (5,413) [b(a)]as[] ? creep
   Fail: (5,412) b(_57162, [b(a)], []) ? creep
   Fail: (5,411) c(_57162, [b(a)], []) ? creep
false.

Провал на [b(a)]as[] мне интересен. Что там тестируют? И... что означает этот синтаксис?

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

Иногда в моем приложении я хотел бы перефразировать неэлегантные предложения. Например, иногда я сталкиваюсь с чем-то вроде ["bake", "that" "many", "pie", "plus", "one"]. Я бы хотел, чтобы DCG обработала это так, как будто вместо этого она столкнулась с ["bake", "x", "pie"]. Так что я мог бы использовать phrase(foo(X), ["x", "pie"]), и если это удастся, я мог бы обернуть его в другое правило выше в грамматике. (Почему бы просто не вызвать правило более высокого уровня для начала? Некоторые из правил более высокого уровня очень медленны в моей грамматике, поэтому я пытаюсь быстро выйти из строя, сначала протестировав правило грамматики более низкого уровня.)

Спасибо заранее за любые советы!


person Erik Germani    schedule 11.03.2021    source источник
comment
Это помогло бы мне понять, к чему вы стремитесь, если бы ваш пример был более ясным. что именно ты хочешь? два шага перевода? сначала перефразировать ввод, а затем разобрать его? или делать перефразировку встроенную в парсинг?   -  person tiffi    schedule 11.03.2021


Ответы (2)


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

Обратите внимание, что они выполняют обработку списка и потребляют элементы в скобках, если они унифицированы с префиксом списка. (и наоборот, они могут сгенерировать элементы в квадратных скобках, если вы запустите DCG в обратном порядке)

as      --> [].           % consumes nothing
as      --> [a], as.      % consumes an atom 'a', then calls rule as//0
b(b(a)) -->      as.      % consumes nothing, then calls rule as//0
c(X)    -->      b(X).    % consumes nothing, then calls rule b//1

Аргументы в круглых скобках являются стандартными аргументами предиката Пролога.

Когда вы звоните

phrase(b(X), [a, a])

Это успешный путь через дерево возможностей:

  • Use b(X) to consume a prefix of [a,a]:
    • X is unified with b(a) and as//0 is called, nothing is consumed.
  • Use the second clause of as to consume a prefix of [a,a]:
    • a is consumed and as//0 is called
  • Use the second clause of as to consume a prefix of [a]:
    • a is consumed and as//0 is called
  • Use the first clause of as to consume a prefix of []:
    • Succeeds without further rule calls

Таким образом, вызов phrase/2 завершается успешно с X=b(a), но b(a) не имеет ничего общего с b и a правил.

А как насчет phrase(c(X), [b(a)]).?

  • Use c(X) to consume a prefix of [b(a)]:
    • Nothing is consumed, b(X) is called.
  • Используйте b(X) для потребления префикса [b(a)]: -X объединяется с b(a) (головы, а не списка), ничего не потребляется, вызывается as.
  • Use as to consume a prefix of [b(a)]:
    • The first clause applies as it consumes nothing, but going down that path eventually will result in failure as we used phrase/2, demanding that the list be empty on success (rather than phrase/3 where we could leave a Rest argument unbound).
    • Второе предложение не применяется, так как оно использует a, но список [b(a)]

Отказ.

Аналогично для phrase(c(X), [b(b(a))]).

Вывод трассировщика:

Call: (5,413) [b(a)]as[] ? creep
Fail: (5,413) [b(a)]as[] ? creep

кажется, указывает на то, что с помощью единственных применимых правил, а именно первого:

as      --> [].

фактическое содержимое списка [b(a)] должно быть равно [] (потому что из-за вызова phrase/2 нам нужен пустой остаток). Возможно, вы видите эффект оптимизатора.

person David Tonhofer    schedule 11.03.2021

Странный вывод трассировщика, похоже, связан с тем, что, по крайней мере, в моем swipl, as объявлен как инфиксный оператор :-)

доказательство:

?- current_op(Prec,Type,as).
Prec = 700,
Type = xfx.

Переименование вашего предиката во что-то другое — я выбрал asif на данный момент — изменяет вывод трассировщика:

?- trace, phrase(c(X), [b(b(a))]).
^  Call: (9) phrase(c(_5760), [b(b(a))]) ? creep
   Call: (12) c(_5760, [b(b(a))], []) ? creep
   Call: (13) b(_5760, [b(b(a))], []) ? creep
   Call: (14) asif([b(b(a))], []) ? creep
   Fail: (14) asif([b(b(a))], []) ? creep
person tiffi    schedule 11.03.2021