Help understaing fails and skipping redoing

I’m using: SWI-Prolog version 9.2.8

I want the code to:
If the condition fails within func2, I want func1 to fail too “immediately”, without any redoing

But what I’m getting is:
If

Res /= []

is false, the program backtracks and tries again, to an earlier (causing an infinite loop).
I think I kind of understand why this happens but I don’t know how else I could fix this

My code (roughly) looks like this, I reduced it so it is much more readable:

func2(X) :-
    func3(X, Res),
    (   Res \= [] ->
        %there are some other functions here to which func2 backtracks to when failing
        func4(X, NX),
        func2(NX)
    ;   fail
    ).

func1(X) :-
    func2(X).

Res = [_|_] is preferable to Res \= [], because it defines what it can be, and prevents e.g. Res = zebra.

Unsure what this means.

Sounds like you want to use \+/1 as a check on the potentials.

That would happen anyway by ->/2, so this line can be removed.

Your code will backtrack on func3/2. Also, if Res\=[] (or, better, Res=[_|_]), it can backtrack on func4/2 and func2/1 (which are inside the “then” part of the if-then-else).

If you want only the first result from func3/2 (that is, no backtracking on func3/2), you can write (func3(X,[_|_])-> ...) (or (func3(X,Res),Res\=[]->...)).

There’s no need to specify fail in the “else” in (... -> ... ; fail); you can omit the “else”: (... -> ...).

Thank you for the responses and the tips.

I apologize, I see that I forgot to clear up some of the details regarding the code.

You are right that the code will backtrack to func3/2, but that only has one implementation, so when viewing it in trace mode, it doesn’t show up so I didn’t notice. However, func4/2 has multiple implementations, for example

% case when X is zero
func4(0, NX) :-
  ...

% case when X is not zero (but due to redoing, the program might still try it with zero)
func4(X, NX) :-
  ...

When func2/1 is called, and Res = [_|_], func4/2 runs, then, func2/1 gets called recursively. When it fails in the recursive call, it backtracks (eventually) to func4/2, and the functions above them, which is what I am trying to avoid.

Also note that there are other functions above func2 that I omitted from my explanation so it’s easier to understand, which I don’t want my program to backtrack to. My goal is that func1/1 should fail, if Res = [_|_] is ever false.

I assume I could place X \= 0, to the other implementations of func4/2 (I think this is what @brebs meant), but when viewing in trace, when redoing, the function still gets called (it just fails immediately). This yields correct results, but I wonder if there are solutions where redoing is skipped entirely

As @peter.ludemann said I could do (func4(X, NX) -> ...) but what if, let’s call it func5/2 is also called just above func4/2, that I also don’t want to backtrack to?

Can use e.g. first-element indexing, with terms, for that.

Need a better explanation of what the program is intended to do. “func1” isn’t meaningful :grinning:

Failing immediately (i.e. identifying failure and so moving on to other possibilities) is a good thing - it’s failing far slower than possible which is bad.

Cuts prevent backtracking - e.g. (!)/0, once/1, (->)/2 - but I can’t tell from the explanation whether the code shouldn’t be rewritten some other way instead.