Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use run_query in streaming mode/limiting number of matches? #2394

Open
lambdaofgod opened this issue Apr 26, 2024 · 3 comments
Open

Comments

@lambdaofgod
Copy link

I've written basic bindings for Python in my project using lib_machine::Machine's run_query.

For queries that return small number of matches it works fine, but when I run a query that returns large or infinite numer of matches the program seems to enter infinite loop.

Is there a way to limit number of matches, or even better, is there a way to explicitly return a stream of matches?
A stream of matches or something that allows for suspended computation seems perfect as it naturally fits returning a generator in Python.

Looking at code I've also seen a server, but I don't know how to run it - maybe this would be a better approach than calling Rust code, what do you think?

@bakaq
Copy link
Contributor

bakaq commented Apr 26, 2024

I don't think Scryer currently has an interface for getting this (what in Rust you would call an iterator). It was postponed from the initial pull request because it wasn't high priority for a lot of use cases. Related: #1880 (comment) #1880 (comment).

One thing you can maybe do is to limit or stream the queries from inside Prolog, although this is not as performant or ergonomic as simply having a run_query() that returns an iterator.

:- use_module(library(iso_ext)).
:- use_module(library(lists)).
:- use_module(library(clpz)).

all_lists_infinite(L) :-
    length(L, _).

all_lists_limited_clpz(L, N) :-
    #Len #>= 0,
    #Len #=< #N,
    label([Len]),
    length(L, Len).

% Very low level (and ugly in my opinion), but more general because
% the predicate that you are limiting doesn't need to be parametrized.
all_lists_limited_bb(L, N) :-
    bb_put(all_lists_count, 0),
    length(L, _),
    bb_get(all_lists_count, Count),
    (   Count > N ->
        % A cut to stop looking for answers
        !, false
    ;   Count1 is Count + 1,
        bb_put(all_lists_count, Count1)
    ).

You could use similar techniques to skip the first N answers, so that you could make an iterator with this, although it would get much slower to get the next answer the further along you go because in the general case you would still need to compute all of the previous answers.

@triska
Copy link
Contributor

triska commented Apr 27, 2024

@lucksus: This could be an interesting candidate for a generalization of the existing interface, and I would greatly appreciate if could take it into account! Thank you a lot!

@UWN
Copy link

UWN commented Apr 30, 2024

Using these bb_ primitives is the entry to non-reentrant code. Use call_nth/2 of library iso_ext in its stead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants