Пролог, строительный список с условными оговорками - PullRequest
7 голосов
/ 17 мая 2011

Мне нужно выполнить домашнее задание, используя пролог (SWI-аромат), и я не могу разобраться с некоторыми вещами.

Например, если я хочу перебрать список и добавить его элементы в другой, но ТОЛЬКО если они удовлетворяют определенному условию, как мне поступить? Я могу добавить их все, или ни одного, но если я добавлю предложение, которое проверяет это условие, вся рекурсия оказывается «ложной». Я понимаю, почему это так, но понятия не имею, как это исправить. В основном то, что я хочу, это:

goal(Stuff) :- do_something(X),
               only_do_this_if_something(Y),
               always_do_this(Z).

В настоящее время, если only_do_this_if_something(Y) терпит неудачу, также не происходит always_do_this(Z), поскольку вся цель становится ложной ...

Ответы [ 4 ]

10 голосов
/ 17 мая 2011

Вы можете использовать структуру if:

<condition> -> (do_something) ; (do_something else)

в этом случае:

goal(Stuff):-
  do_something(X),
  if_something(Y)-> do_this(Y) ; true,
  always_do_this(Z).

или вы просто пишете два предложения вроде:

goal(Stuff):-
  do_something(X),
  conditional_stuff(Y),
  always_do_this(Z).

conditional_stuff(Y):-
  condition(Y),
  do_this(Y).

conditional_stuff(_).
1 голос
/ 17 мая 2011

Если я правильно понимаю, то вам нужен предикат типа include/3:

include(:Goal, +List1, ?List2)
    Filter elements for which Goal succeeds. True if List2 contains
    those elements Xi of List1 for which call(Goal, Xi) succeeds.

Пример использования:

?- include(number, [a(b), 2, _, 1.2, C, '1'], L).
L = [2, 1.2].

Теперь ваша домашняя работа становится «как реализовать include/3».После того, как вы реализовали свою версию include/3, вы можете проверить, соответствует ли она версии SWI, посмотрев ее исходный код: listing(include).

1 голос
/ 17 мая 2011

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

  • Итерация по списку, по одному элементу за раз
  • Установить базовый вариант для рекурсии
  • В одном пункте проверьте, применяются ли условия и что-то сделать, затем продолжите рекурсию
  • В следующем пункте пропустите элемент и продолжите рекурсию

Вы должны либо использовать вырез (!), Чтобы запретить возврат, либо явно проверить, что условие не применяется в последнем пункте.

Обратите внимание, что вы сказали, что хотели бы иметь выходной список с элементами, к которым применялось что-то (что не то, что вы написали в своем коде) ...

Применение этого шаблона к вашей проблеме выглядело бы примерно так:

myRecursion([], []). % This is the base case
myRecursion([Item|Tail], [Item|NTail]):-
  something_applies(...),
  do_something(...),
  only_do_this_if_something(...),
  always_do_this(...).
  myRecursion(Tail, NTail).
myRecursion([Item|Tail], NTail):-
  not(something_applies(...)),
  do_something(...),
  always_do_this(...),
  myRecursion(Tail, NTail).
0 голосов
/ 17 мая 2011

попробуйте предикат ignore / 1:

goal(Stuff) :-
    do_something(X)
    ignore(only_do_this_if_something(Y)),
    always_do_this(Z).

ignore / 1 вызывает единственный аргумент и завершается успешно всякий раз, когда он не работает или нет:

ignore(X) :- X, !.
ignore(_).
...