Behavior of once(concurrent_and( vs. first_solution(

Hi!

I noticed “once(concurrent_and(” behaves like “first_solution(”.

It probably means that when “concurrent_and” returns a result and “once” commits to it then concurrent_and will stop and cleanup the remaining threads. I tried various experiments with timings and even print calls within the threads to confirm that. Very nice that it does, but also unexpected, does anybody have a better idea of why it is the case (or not the case for an particular example) and whether that corresponds to be the intended behavior?

Best regards,

Patrick

Could you start by sharing a reproducible example?

Attached it is. I apologize in case the Prolog code looks a bit exotic, it is the output of a compiler that compiles MeTTa code to Swi-Prolog code:

Why unexpected? This is fundamental to Prolog, with choicepoints and backtracking, and having !/0 which can remove choicepoints.

once/1 is a convenient wrapper which uses !/0, as can be seen:

?- listing(once).
:- meta_predicate once(0).

system:once(Goal) :-
    call(Goal),
    !.

once/1 is just doing its normal task: to succeed at most once.

Here’s an example to show subtleties:

?- concurrent_and(member(X, [1,2,3]), Y = X).
X = Y, Y = 1 ;
X = Y, Y = 2 ;
X = Y, Y = 3 ;
false.

vs:

?- once(concurrent_and(member(X, [1,2,3]), Y = X)).
X = Y, Y = 1.
1 Like

I see, thank you for clarifying! I agree it is consistent with the semantics of once, but I was not sure if that also works for multi-threaded constructs like concurrent_and, I am glad it does.

Best regards,

Patrick