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最终将被执行。

样本回溯树

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

Abbreviation:
       Bar1 failed : F
       Bar2 executed : E
4

1 回答 1

1

You're looking for what's known as "soft cut",

A *-> B ; C.

This is equivalent to (A,B) ; (\+A,C): if A succeeds at least once, the above is equivalent to A,B. If not, it's equivalent to just C. The goal A is not retried.

Simple if construct allows the test predicate to succeed only once:

A -> B ; C.

is equivalent (almost - see you manual for details) to (once(A),B) ; (\+A,C), except that the goal A isn't retried.

Thus your case shall be

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

addition: Some Prolog implementations might not have this construct *-> available (e.g. gprolog). In that case I see two possibilities. Either

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

although it would retry A, or (writing goal(X) for A)

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

Of course the order of side-effects will be changed by this. The name L of the variable should be chosen such that it does not appear free in B.

于 2012-06-04T18:22:26.073 回答