I’m getting stymied by a task that I’d find simple in other languages, but I just don’t know what the best way is to implement it in Prolog. Specifically, I want to perform several processing steps on a stream of data, each of which may or may not change the cardinality of the dataset, and which may or may not be deterministic, and I’d like them to operate without having to hold the entire stream (or, worse, multiple copies of the stream) in memory. Basically, I want to do the following:
process_stream(List0, Processed) :-
transformation1(List0, List1), % no cut
transformation2(List1, List2), % no cut
transformation3(List2, Processed).
only, without storing the whole list in between. If all the streams had the same cardinality, I could just do:
process_stream([H0|T0], [HP|TP]) :-
transform1(H0, H1),
transform2(H1, H2),
transform3(H2, HP),
process_stream(T0, TP).
process_stream([], []).
but that only works if the lists remain in lockstep, and each can process a single element at a time, without context.
In, say, Python or C#, I could just use generators/iterators, with each transformer consuming the elements it needs before yielding whatever values it can produce to its output. I’ve glanced at library(lazy_lists)
, but that really seems geared only towards deterministic processes, and especially those that can opportunistically pull in a whole block of data at once. Basically, for reading from file/network. And honestly, constraint programming in general seems pretty ill-suited to this, because unless you are dealing with a det/semidet source and you use extra-logical storage for stream blocks, it only ever works in post-hoc mode. Basically, if you had this definition for transform2
:
transform2(foo, bar).
transform2(apple, banana).
transform2(bear, eel).
and you called it with a delayed/attributed variable in the first argument that would eventually resolve to ‘bear’, Prolog would have no choice but to try unifying it with foo, calling the unification hook, failing to unify foo = bear
, undo the H1 = foo
unification, try it again with H1 = apple
, and so on. Not precisely the most practical or efficient way to go about things.
So, how do I do this in Prolog? And, to extend it a little, how do I do it with DCGs, which are even more limited in their calling convention?