L = [1,2,3], member( X, L ).
L = [1,2,3], member( X, L ), member( X, L ).
Would both of them have essentially the same complexity and execution time? Or is the first one O(n) whereas the second is O(n^2)? Does SWI (or any other PL implementation) have logic that avoids a redundant second iteration through the members of L? If so, how is this done?
In the second query, the first member(X,L) will instantiate X, so the second member(X,L) will simply look for X in L rather than backtracking through all possibilities. But it’ll still be O(n^2) because the search has to go through all items (memberchk(X,L) would stop as soon as X is found, so it’d be a bit faster and also wouldn’t leave a choicpoint).
Now, try adding a table/1 declaration and you’ll see a different trace – the table/1 will result in a kind of memoization. In this particular situation, it’s not clear that there’ll be any performance advantage because the memoization will still need to match against the entire L list and that’ll be O(n). But for more complex queries, there can be a big performance improvement.