Wrap predicate example by GPT

Can you use the wrap_predicate library predicate?

Yes, you can use the wrap_predicate library predicate in SWI-Prolog to wrap a predicate with a precondition. Here’s an example:

:- use_module(library(wrap_predicate)).

% Define the original add predicate
add(X, Y, Sum) :- Sum is X + Y.

% Define a precondition that checks if both arguments are positive numbers
positive_numbers_only(X, Y) :-
    X > 0, Y > 0.

% Wrap the add predicate with the positive_numbers_only precondition
wrap_predicate(add/3, [positive_numbers_only], _).

% Call the wrapped add predicate with positive arguments
?- add(2, 3, Sum).
Sum = 5.

% Call the wrapped add predicate with a non-positive argument
?- add(2, -3, Sum).
ERROR: positive_numbers_only/2: Both arguments must be positive numbers

In this example, we first load the wrap_predicate library predicate by calling :- use_module(library(wrap_predicate)). Then, we define the original add predicate as before.

Next, we define a new predicate called positive_numbers_only that takes two arguments and succeeds if both arguments are positive numbers.

To wrap the add predicate with the positive_numbers_only precondition, we call wrap_predicate(add/3, [positive_numbers_only], _). The first argument of wrap_predicate specifies the predicate and its arity (in this case, add/3), the second argument is a list of preconditions (in this case, positive_numbers_only), and the third argument is an output variable that is not used in this example.

Finally, we can call the wrapped add predicate with positive and non-positive arguments, and observe that it behaves as expected.

Note that the wrap_predicate library predicate is a convenient way to wrap a predicate with a precondition, but it is not as flexible as defining the wrapper function explicitly, as in the previous examples. For example, it does not allow you to define a custom error message when the precondition fails.

This doesn’t seem correct for several reasons:

  1. The library is prolog_wrap, not wrap_predicate
  2. The predicate to wrap is wrap_predicate/4, not wrap_predicate/3
  3. The wrap predicate isn’t just a pre-condition, it needs to call the original to use the original functionality.
  4. It isn’t even calling wrap_predicate/3, it’s asserting a fact

I guess basically it “hallucinated” the API whole-cloth and also doesn’t quite understand how calling predicates works (also not sure where that error message in the negative case is supposed to come from).

2 Likes

What is the purpose of the topic?

Sometimes others will post such, show that the code does not work, point out the mistakes, show how to correct them and then demonstarte the correct working code.

Sometimes others will post such and ask for help, yet there is no follow up question.

I have no idea why this was posted but as @jamesnvc it has many mistakes.

I found no example in the documentation, so i thought to have GPT generate one, so i get an example use, that i can adapt for my use.

Clearly, its not trained with enough data on prolog to generate the right thing.

I guess, python has many more data points … and was corrected more often with human in the loop reinforcement training.

But, since the documentation is often hard to penetrate, having GPT generate examples would be really neat.

Here is working code for wrap_predicate/4 created in the spirit of the what the GPT generated.

Rember that when working with wrappers, if a wrapper that should be removed was not then you may get unexpected results when using the wrapped predicate. Often during development for such cases killing the top level and starting over is the fastest way to remove the wrapper.

File: some_module.pl

:- module('some_module',
    [check/1]
).

% Demonstrate basic usage of sum/3 with two negative numbers.
% Result:
%    Sum of -1 and -5 is -6
%    true.
check(01) :-
    X = -1,
    Y = -5,
    add(X,Y,Sum),
    format('Sum of ~d and ~d is ~d~n',[X,Y,Sum]).

% Demonstrate basic usage of positive_numbers_only/1 with two positive numbers.
%    true.
check(02) :-
    positive_numbers_only(1,1).

% Demonstrate basic usage of positive_numbers_only/1 with first number negative and second number positive.
% Result:
%    Both arguments must be positive numbers
%    false.
check(03) :-
    positive_numbers_only(-1,1).

% Demonstrate basic usage of positive_numbers_only/1 with first number positive and second number negative.
% Result:
%    Both arguments must be positive numbers
%    false.
check(04) :-
    positive_numbers_only(1,-1).

% Demonstrate basic usage of positive_numbers_only/1 with both numbers negative.
% Result:
%    Both arguments must be positive numbers
%    false.
check(05) :-
    positive_numbers_only(-1,-1).

% Demonstrate a wrapper that does nothing.
% Result:
%    Sum of -4 and -2 is -6
%    true.
check(06) :-
    wrap_predicate(add(X,Y,Sum),do_nothing,Original_goal,Original_goal),
    X = -4,
    Y = -2,
    add(X,Y,Sum),
    format('Sum of ~d and ~d is ~d~n',[X,Y,Sum]),
    unwrap_predicate(add/3,do_nothing).

% Demonstrate a wrapper that uses positive_numbers_only/2 as a condition before calling original add/3 goal.
% Result:
%    Sum of 2 and 1 is 3
%    true.
check(07) :-
    Body =
    (
        positive_numbers_only(X,Y)
    ->
        Original_goal
    ;
        false
    ),
    wrap_predicate(add(X,Y,Sum),wrap_example_01,Original_goal,Body),
    X = 2,
    Y = 1,
    (
        add(X,Y,Sum)
    ->
        format('Sum of ~d and ~d is ~d~n',[X,Y,Sum])
    ;
        true
    ),
    unwrap_predicate(add/3,wrap_example_01).

% Demonstrate a wrapper that uses positive_numbers_only/2 as a condition before calling original add/3 goal.
% Result:
%    Both arguments must be positive numbers
%    false.
check(08) :-
    Body =
    (
        positive_numbers_only(X,Y)
    ->
        Original_goal
    ;
        false
    ),
    wrap_predicate(add(X,Y,Sum),wrap_example_02,Original_goal,Body),
    X = -4,
    Y = -2,
    (
        add(X,Y,Sum)
    ->
        format('Sum of ~d and ~d is ~d~n',[X,Y,Sum])
    ;
        true
    ),
    unwrap_predicate(add/3,wrap_example_02).

% ----------------------------------------------------------------------------

add(X,Y,Sum) :-
    Sum is X + Y.

positive_numbers_only(X,Y) :-
    (
        X > 0,
        Y > 0
    ->
        true
    ;
        format('Both arguments must be positive numbers~n',[]),
        false
    ).

Exmaple run

Welcome to SWI-Prolog (threaded, 64 bits, version 9.1.6)
...

?- working_directory(_,'C:/Users/Groot').
true.

?- ['some_module'].
true.

?- check(1).
Sum of -1 and -5 is -6
true.

?- check(2).
true.

?- check(3).
Both arguments must be positive numbers
false.

?- check(4).
Both arguments must be positive numbers
false.

?- check(5).
Both arguments must be positive numbers
false.

?- check(6).
Sum of -4 and -2 is -6
true.

?- check(7).
Sum of 2 and 1 is 3
true.

?- check(8).
Both arguments must be positive numbers
false.

EDIT

For me, personally, it seems like creating a prompt for ChatGPT that correctly uses the Wrapped closure with wrap_predicate/4 takes more effort than simply coding it by hand. I find it difficult to explain the concept to ChatGPT in a way that it understands. However, I have noticed that many advanced concepts of Prolog can be just as challenging to convey to ChatGPT, making it faster to manually write the code.

1 Like

When you entered the above prompt was it on ChatGPT? Was the prompt given latter in a conversation?

Giving ChatGPT that as a prompt in a new conversation results in a completion for Python, yet the completion given by you is for what appears to be Prolog, so somewhere along the line the GPT probably gained knowlege that drew attention to Prolog.

If you plan to post more such examples then please note the specific GPT used and even the version if known. Also please test run the code and note if it works correctly or geneates errors. What would be even better is to also fix the code if it does not work and demonstarte it working.

Thanks,

Yes, i posted mid conversation – first ChatGPT generated python, then i asked for swi-prolog, where it generated something that was not using the wrap_predicate, and then I asked to specifically use it – which is the prompt segment included in the post.

The key issue here is that I didn’t know how ot use wrap_predicate – the documentation is too cryptic for me – but, I realized that what was generated isn’t going to work either.

Dan

Did you see my working examples given above?

If they don’t make sense ask questions. I am sure many others would like to understand wrap_predicate/4 and have similar questions.

If you want a good example to try on your own, create a wrapper that writes to the terminal when a predicate from a specific module you create is called, the arguments and then when the predicate is exited. I note specfic module you create because you can easily wind up in an infinte loop if not careful. It would be similar to what trace/0 does but would lack the indenting. One can learn alot about wrappers creating such an example.

I expect the best way to prompt correct usage of a predicate is to just use that predicate correctly, in the prompt.

ok. great. thank you

My plan is to separate out error handing from core predicate declaration, so that predicates and error handing strategy are separated.