listrecursionprologreturn-valueswi-prolog

How to create a list dynamically in Prolog?


I have looked at the gazillions of other similar questions, but I haven't found a working solution, so I am asking this:

I have a rule:

check_prime(X) :-
  X > 0,
  X0 is X - 1, 
  (X =:= 1 -> true; 
   X =:= 2 -> true; 
   foreach(between(2, X0, T), X mod T =\= 0) -> true; false).

then I want to run:

B is [0], 
foreach( between(1, 50, T), 
         (check_prime(T) -> B2 = [B, T], write(B2); !)).

What this successfully does is write pairs of [0, primeNumber] to the console. I can alternatively do this:

B is [0],
foreach( between(1, 50, T), 
         (check_prime(T) -> (write(T), write(", ")); !)).

which actually prints everything in a pretty way, minus the lack of being a list, and the extra comma at the end.

This writing function is working through the solutions of check_prime(T) recursively, one solution at a time. I want to make a list of all of these solutions, but no matter what I try, I either cannot get object permanence (the written atom is something like _31415926), or I encounter a variety of errors.

How do I dynamically create a list of prime numbers since each one is found recursively?

Edit:

Yes, this is all the code I am using: enter image description here

enter image description here

I have tried varying the "if true" branch, but it keeps having issues:

enter image description here enter image description here

enter image description here


Solution

  • How do I dynamically create a list of prime numbers?

    Make check_prime check if a number is prime (and nothing else):

    check_prime(1).
    check_prime(2).
    check_prime(X1) :-
        X1 > 2,
        succ(X0, X1),
        forall(between(2, X0, N), \+ (0 is X1 mod N)).
    

    Then use it to make a list of primes, e.g:

    ?- findall(X, (between(1, 50, X), check_prime(X)), Primes).
    Primes = [1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
    

    or

    primes_to(X, Primes) :-
        numlist(1, X, Nums),
        include(check_prime, Nums, Primes).
    
    ?- primes_to(50, Primes).
    Primes = [1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
    

    if you actually do want to do it recursively instead of conveniently, a builder that adds a counter onto the list of primes if the counter is prime, and doesn't if it isn't:

    primes_to(0, []).
    
    primes_to(Counter, [Counter|Primes]) :-
        check_prime(Counter),
        Counter0 is Counter - 1,
        primes_to(Counter0, Primes).
    
    primes_to(Counter, Primes) :-
        \+ check_prime(Counter),
        Counter0 is Counter - 1,
        primes_to(Counter0, Primes).
    
    
    ?- primes_to(50, Primes).
    Primes = [47, 43, 41, 37, 31, 29, 23, 19, 17, 13, 11, 7, 5, 3, 2, 1]