Search code examples
prologquicksorthigher-order-functions

SWI-Prolog partition predicate works differently in REPL than in programme


I imlemented quicksort using SWISH this way:

qsort([],[]).
qsort([H|T],S) :-
  partition([X,O]>>compare(O,X,H),T,L,E,G),
  qsort(L,A),
  qsort(G,Z),
  append([A,[H|E],Z],S).

main :-
  length(L,22),
  maplist(random(0,9),L),
  qsort(L,S),
  maplist(writeln,[L,S]).

It doesn't work correctly. The input and output lists are the same. However when I run this in the REPL there on the right: length(S,22), maplist(random(0,9),S),[H|T]=S, partition([X,O]>>compare(O,X,H),T,L,E,G).

the random lists do get sorted. Whence the difference?


Solution

  • When the second clause for the qsort/2 predicate is compiled, there's no information on H other than it's a variable when compiling the lambda expression. Any variable occurring in the lambda expression that's not find in a local lambda parameter must be declared using the {}/1 construct. But when running your query at the top-level interpreter, by the time the lambda expression is interpreted, H is bound and thus no longer a variable (making the use of the {}/1 construct unnecessary).

    Note that there are several details here at play that are out of scope of the lambda library itself: (1) is the compiler recognizing at compile time that you're calling a meta-predicate with an argument that's a lambda expression? (2) how's a top-level query interpreted? Is the full query first fully compiled or is it meta-interpreted? These details depend on the system itself.