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/1
predicate returns another predicate (int_seq/3
) that acts as our closure. This predicate keeps track of the current state (the value ofI
).int_seq/3
takes three arguments: the current stateI
, the next valueNext
, and the new stateNewI
. It increments the state and unifiesNext
with the new value.In the
main
predicate, we create our closure by callingint_seq(NextInt)
.NextInt
is 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
NextInt
multiple times using thecall/2
predicate. 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
NewInts
and 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
1
This 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.