Closures in Prolog
% This predicate int_seq/1 returns another predicate, which
% we define anonymously in the body of int_seq/1. The
% returned predicate closes over the variable I to form a closure.
int_seq(NextInt) :-
NextInt = int_seq(0).
int_seq(I, Next, NewI) :-
NewI is I + 1,
Next = NewI.
% We call int_seq/1, assigning the result (a predicate) to NextInt.
% This predicate captures its own I value, which will be updated
% each time we call NextInt.
main :-
int_seq(NextInt),
% See the effect of the closure by calling NextInt a few times.
call(NextInt, N1),
writeln(N1),
call(NextInt, N2),
writeln(N2),
call(NextInt, N3),
writeln(N3),
% To confirm that the state is unique to that particular
% predicate, create and test a new one.
int_seq(NewInts),
call(NewInts, N4),
writeln(N4).In Prolog, we can simulate closures using predicates that carry state. Here’s how the code works:
The
int_seq/1predicate returns another predicate (int_seq/3) that acts as our closure. This predicate keeps track of the current state (the value ofI).int_seq/3takes three arguments: the current stateI, the next valueNext, and the new stateNewI. It increments the state and unifiesNextwith the new value.In the
mainpredicate, we create our closure by callingint_seq(NextInt).NextIntis now bound to a predicate that we can call to get the next integer in the sequence.We demonstrate the effect of the closure by calling
NextIntmultiple times using thecall/2predicate. Each call increments the internal state and returns the next number in the sequence.To show that each closure maintains its own state, we create a new closure
NewIntsand call it once, showing that it starts from the beginning of the sequence.
To run this program:
$ swipl -q -t main -f closures.pl
1
2
3
1This example demonstrates how Prolog can simulate closures using predicates that maintain state between calls. While Prolog doesn’t have built-in support for closures in the same way as some other languages, this approach allows us to achieve similar functionality.