Call a predicate if another predicate failed

2019-09-07 02:45发布

How can I call a predicate if all calls to another predicate failed?

I have:

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

What I want :

  • at any time, If bar1/2 has succeded, bar2/3 will never be executed.
  • if all bar1/2 calls failed, then bar2/3 will eventually be executed.

Sample Backtracting tree

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

Abbreviation:
       Bar1 failed : F
       Bar2 executed : E

标签: prolog
1条回答
ら.Afraid
2楼-- · 2019-09-07 03:15

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.

查看更多
登录 后发表回答