2012-06-04 2 views
0

Как я могу вызвать предикат, если все вызовы другого предиката не удались?Вызвать предикат, если сбой другого предиката

у меня есть:

foo(A, B, C, D) :- 
    (bar1(Y,Z); bar2(L, K, M)), 
    foo(A, B, C, D). 

Что я хочу:

  • в любое время, если bar1/2 уже преуспели, bar2/3 никогда не будет выполнена.
  • если все bar1/2 звонки не удались, тогда bar2/3 в конечном итоге будет выполнен.

Образец Backtracting дерево

  root           root     
                  | 
     / \           | 
     / \   all bar1 failed     | 
     /  \           | 
     /| \  \  ===>>>======>>>>     | 
    /| \  \          | 
     F F F  F          E 
time 0 1 2  3          4 

Abbreviation: 
     Bar1 failed : F 
     Bar2 executed : E 
+2

Я думаю, вы ищете «если bar1, то true else bar2». Остальное должно быть легко с ответом на ваш предыдущий вопрос ... – twinterer

ответ

1

Вы ищете то, что известно как "мягкий разрезом",

A *-> B ; C. 

Это эквивалентно (A,B) ; (\+A,C): если A удастся, по крайней мере один раз, выше, эквивалентно A,B. Если нет, это эквивалентно только C. Цель A не повторена.

Простой if конструкция позволяет тест предикат успеха только один раз:

A -> B ; C. 

эквивалентно (почти - см вы руководство для деталей) к (once(A),B) ; (\+A,C), за исключением того, что цель A не повторен.

Таким образом, ваше дело должно быть

foo(A, B, C, D) :- 
    (bar1(Y,Z) *-> true ; bar2(L, K, M)), 
    foo(A, B, C, D). 

дополнения: Некоторых реализации Пролога могут не иметь эту конструкцию *-> доступные (например gprolog). В этом случае я вижу две возможности. Либо

(A , B) ; (\+A , C) 

хотя бы повторить A, или (написание goal(X) для А)

bagof(g(X), goal(X), L) -> (member(g(X), L), B) ; C 

Конечно порядок побочных эффектов будет изменен этим. Имя L переменной должно быть выбрано так, чтобы оно не было бесплатным в B.

+0

Когда я пробовал ваш комментарий к gprolog, он дает синтаксическую ошибку. Есть ли способ, я могу поймать тот же эффект? –

+0

Я думаю, вы можете написать этот эквивалентный код, '(A, B); (\ + А, С) '. Он просто повторит попытку «A», поэтому любые побочные эффекты будут происходить дважды. –

+0

Или попробуйте это '(bagof (g (Y, Z), bar1 (Y, Z), L) -> член (g (Y, Z), L), true, bar2 (L, K, M)), Foo (А, В, С, D) '. Работает в SWI Prolog. «истина» есть как заполнитель; он не нужен сам по себе. –

Смежные вопросы