That’s an excellent paper with some really solid work behind it.
However, the idea is not original. Here are filter/2 and map/2
expressed using a functional-programming preprocessor for Prolog.
filter(, P) = [].
filter([H|T], P) = [H|filter(T, P)] :- call(P, H), !.
filter([|T], P) = filter(T, P).
map(, F) = .
map([H|T], F) = [call(F, H) | map(T, F)].
This was translated, back in, oh, 1990? to
filter(, _P, R) :- R = .
filter([H|T], P, R) :- call(P, H), !, R = [H|T2], filter(T, P, T2).
filter([_|T], P, R) :- filter(T, P, R).
map(, F, R) :- R = .
map(H|T], F, R) :- call(F, H, H2), R = [H2|T2], map(T, F, T2).
where R is the “hole”.
To the best of my recollection – it’s years since I had either logix or Parlog –
the logix implementation of flat concurrent Prolog and Parlog did the same thing.
Logix at least had to, since in FCP all call are tail calls. Indeed,
“hole passing” was a major technique in FCP. My recollection of Parlog is now
hazy, but I recall the management of holes being part of how Parlog did
synchronisation.