#!/usr/bin/env perl
use v5.38;
use lib ('../lib', 'lib');
use Test2::V0 '!call';
no warnings 'redefine';
no warnings 'prototype';
use Logic::Relational qw(variable call all);
use Logic::Relational::Program;

# 1. Define an infinite natural numbers generator: 0, 1, 2, 3, ...
my $p = Logic::Relational::Program->new;
$p->generator(
    'nats', 1,
    sub ($n) {
        my $curr = 0;
        return sub {
            return [ $curr++ ];
        };
    }
);

# Querying the infinite generator and limiting using our loop.
# It should terminate immediately and not loop infinitely when we ask for the first 5 numbers.
my $val = variable('val');
my $q   = $p->query( call( nats => $val ) );

my @sols;
while ( my $sol = $q->next ) {
    push @sols, $sol->value($val);
    last if @sols == 5;
}

is( \@sols, [ 0, 1, 2, 3, 4 ], 'Infinite generator yields elements lazily' );

# 2. Test backtracking over the infinite generator.
# We want numbers that are both generated by nats and satisfy a predicate.
# We'll assert some facts: even(2), even(4).
# We query: nats(V), even(V).
$p->fact( even => 2 );
$p->fact( even => 4 );

my $val2 = variable('val2');
my $q2   = $p->query( all( call( nats => $val2 ), call( even => $val2 ) ) );

my @even_sols;

# We collect the first 2 solutions.
while ( my $sol = $q2->next ) {
    push @even_sols, $sol->value($val2);
    last if @even_sols == 2;
}

is( \@even_sols, [ 2, 4 ],
    'Backtracking over infinite generator works lazily' );

done_testing;
