ChatGPT prompts - SWI-Prolog (2)

PLDoc

Prompt

What is SWI-Prolog PLDoc?

ChatGPT Completion

SWI-Prolog PLDoc is a documentation tool for the Prolog programming language, specifically for the SWI-Prolog implementation. It generates documentation for Prolog source code in the form of HTML pages that can be easily browsed and searched. PLDoc uses comments in the Prolog code to extract documentation information, which it then formats and presents in a user-friendly manner. PLDoc allows you to add descriptive text and examples for predicates, modules, and other Prolog constructs, making it easier for others (and yourself) to understand and use your code. It also provides features for cross-linking between related predicates and modules, making it easier to navigate through the documentation.

Prompt

Create predicate makeConnections/1.

ChatGPT Completion

makeConnections(Line) :-
    line(name(Line), _, stations(Stations)),
    makeConnections(Stations).

:- dynamic connection/2.

makeConnections([_]).
makeConnections([Start,End|Rest]) :-
    (
        connection(Start,End), !
    ;
        assert(connection(Start, End))
    ),
    makeConnections([End|Rest]).

Prompt

Create PLDoc for makeConnections/1

ChatGPT Completion

The following PLDoc can be added to the code to provide documentation for the makeConnections/1 predicate:

%! makeConnections(+Line:atom) is det.
%
%  Connect the stations of the given Line. The line must be represented as the name
%  of the line in the database. The stations must be represented in a list as the
%  stations(List) term in the database. This predicate will dynamically assert
%  connections between the stations in the List, if they do not already exist.
%
%  @param Line The name of the line for which connections should be made.
%  @throws error if the line is not present in the database.
%  @see line/3 for more information about the line/3 predicate.
%  @see connection/2 for information about the dynamic connections.
%  @author Your Name

With these comments in place, PLDoc will generate a page that describes the makeConnections/1 predicate and how to use it. The comments include information about the input parameter, what the predicate does, and any relevant information for using the predicate.

Prompt

What at the steps to see the PLDoc for makeConnections/1 as an HTML page?

ChatGPT Completion

The following steps can be used to generate the PLDoc for makeConnections/1 as an HTML page:

  1. Start SWI-Prolog: Open a terminal or command prompt and start the SWI-Prolog interpreter by running the swipl command.
  2. Load the source code: Load the source code file that contains the makeConnections/1 predicate into the SWI-Prolog interpreter using the consult/1 predicate. For example, if the source code is stored in a file named connections.pl, you can load it with the following command: ?- consult(connections).
  3. Generate the PLDoc: Use the pldoc predicate to generate the PLDoc for the source code. For example, you can generate the PLDoc for the connections.pl file with the following command: ?- pldoc(connections).
  4. View the PLDoc: Open a web browser and navigate to http://localhost:3000/doc/, where you can browse the PLDoc for the makeConnections/1 predicate and other predicates in the source code.

Note: The pldoc predicate is part of the pldoc library in SWI-Prolog, so you may need to install the library if it is not already installed. You can do this by running ?- pack_install(pldoc). in the SWI-Prolog interpreter.

The response is in the ball park but there is a better answer from here.

Example done on Windows 10

  1. Start a command prompt
  2. Use Windows cd batch command to change to the directory with the Prolog files.
  3. Use swipl to create the HTML, start a HTTP server and load the page into an Internet browser, E.g.
C:\Users\Groot>swipl -pldoc london_tube.pl
% Started server at http://localhost:63099/pldoc/
Warning: c:/users/eric/appdata/local/swi-prolog/pack/prolog_library_collection/prolog/dict.pl:60: PlDoc: failed to process structured comment:
%! dict_get(?Keys:or([atom,list(atom)]), +Dict:dict, -Value:term) is nondet.
%! dict_get(+Keys:or([atom,list(atom)], +Dict:dict, +Default:term, -Value:term) is semidet.

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

1 ?-

This will start my default Internet browser and load the URL: http://localhost:63099/pldoc/doc/_CWD_/index.html

Click on a Prolog file name

Since london_tube.pl does not export any predicates they are considered private. To see private predicates in the upper right click on
image

Symbolic Computation

This next prompt is to demonstrate how naturally Prolog can do symbolic computation and see if ChatGPT could generate working code. Remember when ChatGPT gives examples of code being run it is not actually run then copied into the completion, there is a good chance it will be a hallucination.

Prompt

Create Prolog predicate to do a Calculus derivative, demonstrate and explain.

ChatGPT Completion

In Prolog, you can define a predicate that calculates the derivative of a mathematical expression using the symbolic differentiation rules. Here’s an example of a predicate that calculates the derivative of a polynomial expression:

% Derives an expression
derive(X, X, 1).
derive(C, X, 0) :- number(C).
derive(A+B, X, DA+DB) :- derive(A, X, DA), derive(B, X, DB).
derive(A-B, X, DA-DB) :- derive(A, X, DA), derive(B, X, DB).
derive(A*B, X, A*DB + DA*B) :- derive(A, X, DA), derive(B, X, DB).
derive(A^N, X, N*A^(N-1)*DA) :- number(N), N >= 1, derive(A, X, DA).

This predicate uses the rules of symbolic differentiation, such as the power rule, the sum rule, and the product rule, to calculate the derivative of a polynomial expression. For example, to find the derivative of the expression x^2 + 2x + 1 with respect to x, we can query the predicate as follows:

?- derive(x^2 + 2*x + 1, x, D).
D = 2*x + 2.

This means that the derivative of the expression x^2 + 2x + 1 with respect to x is equal to 2x + 2.

Example run using SWI-Prolog

?- derive(x^2 + 2*x + 1,x,D).
D = 2*x^(2-1)*1+(2*1+0*x)+0 ;
false.

That is actually a correct answer, it just needs to be simplified. Every production quality symbolic processor I am aware of also has predicates to simplify the result. Those predicates are missing in the code given. Also an evaluation step is often done as needed. Lastly the output of the format will modify the result as expected by humans, e.g. x^1 would just display as x For such code in Prolog see

The ChatGPT code is also missing some of the standard derivative rules. If you try to use the ChatGPT code with real world problems you will quickly find that you need the other rules.

library(persistency)

Prompt

What does SWI-Prolog library(persistency) do?

ChatGPT Completion

The SWI-Prolog library(persistency) provides a framework for storing and loading Prolog terms from disk, which allows data to persist across multiple program runs.

The persistency library is designed to provide a simple and efficient solution for storing large amounts of data that may not fit entirely in memory. It achieves this by using a combination of memory-mapped files and Prolog term serialization to write and read data to and from disk.

The persistency library provides two main predicates: db_attach/2 and db_sync/1.

The db_attach/2 predicate is used to attach a Prolog database to a file on disk. Once attached, the database can be updated and queried using normal Prolog predicates. Changes made to the database are automatically stored on disk, and can be retrieved on subsequent program runs.

The db_sync/1 predicate is used to synchronize any changes made to the database with the file on disk. This ensures that all changes are safely stored on disk and can be retrieved in subsequent program runs.

In summary, the library(persistency) in SWI-Prolog provides a way to store and retrieve Prolog data structures to disk, which can be useful for applications that need to persist data between program runs.

Note: There are some invalid statements in

The persistency library is designed to provide a simple and efficient solution for storing large amounts of data that may not fit entirely in memory. It achieves this by using a combination of memory-mapped files and Prolog term serialization to write and read data to and from disk.

See: Is ChatGPT just wrong about library(persistency)?

Prompt

For SWI-Prolog using library(persistency) create a program to prompt for some string from a terminal and persist them. Then close down the program. Start the program up again and show the string back on the terminal. Show how to run the code. Explain how the code works.

ChatGPT Completion

Sure, here’s an example program that prompts for a string, stores it in a persistent database, closes the program, and then on subsequent runs, retrieves the stored string and displays it on the terminal:

:- use_module(library(persistency)).

:- persistent
       my_string(value:atom).

% Attach the database to a file
:- db_attach('my_db.pl', []).

% Prompt for a string and store it in the database
prompt_and_store_string :-
    write('Enter a string: '),
    read_string(user_input, '\n', '\r', _, String),
    assert_my_string(String),
    db_sync.

% Retrieve the string from the database and display it
retrieve_and_display_string :-
    my_string(String),
    format('The stored string is: ~w~n', [String]).

% Run the program
main :-
    prompt_and_store_string,
    halt.

% On subsequent runs, retrieve and display the string
:- initialization(retrieve_and_display_string).

To run this program, save it to a file named persist_example.pl, and then load it into SWI-Prolog using the consult predicate:

?- consult('persist_example.pl').
true.

Then, call the main predicate to prompt for a string and store it in the persistent database:

?- main.
Enter a string: Hello, world!
true.

This will store the string “Hello, world!” in the persistent database file my_db.pl. Next, exit SWI-Prolog by typing halt. at the prompt.

?- halt.

Finally, start up SWI-Prolog again and the program will automatically retrieve and display the stored string:

?- consult('persist_example.pl').
The stored string is: Hello, world!
true.

Here’s how the code works:

The library(persistency) is loaded and the persistent predicate is used to define a persistent data structure for storing an atom (a string).
The db_attach/2 predicate is used to attach the database to a file named my_db.pl. If the file does not exist, it will be created.
The prompt_and_store_string/0 predicate is defined to prompt the user for a string, assert it to the database, and synchronize the database with the file on disk using db_sync/0.
The retrieve_and_display_string/0 predicate is defined to retrieve the stored string from the database and display it on the terminal using format/2.
The main/0 predicate is defined to call prompt_and_store_string/0 and then exit the program using halt/0.
The :- initialization(retrieve_and_display_string/0) directive is used to automatically call retrieve_and_display_string/0 when the program is started up again.

For the most part the code is correct except for two minor problems.

  1. my_string(value:atom). should be my_string(value:string).
  2. There is no db_sync/0 predicate. Personally I use db_sync/1 only on rare occasions.

Also put the corrected code in a module named example but should have asked for that in the prompt; no fault of ChatGPT.

Corrected code

:- module(example,[main/0]).

:- use_module(library(persistency)).

:- persistent
    my_string(value:string).

% Attach the database to a file
:- db_attach('my_db.pl', []).

% Prompt for a string and store it in the database
prompt_and_store_string :-
    write('Enter a string: '),
    read_string(user_input, '\n', '\r', _, String),
    assert_my_string(String).

% Retrieve the string from the database and display it
retrieve_and_display_string :-
    my_string(String),
    format('The stored string is: ~w~n', [String]).

% Run the program
main :-
    prompt_and_store_string,
    halt.

% On subsequent runs, retrieve and display the string
:- initialization(retrieve_and_display_string).

Example run of corrected code using SWI-Prolog

?- [example].
Warning: c:/users/groot/example.pl:50: Initialization goal failed
true.

?- example:main.
Enter a string: Hello, world!

After pressing enter the predicate completes, halt is called shutting down SWI-Prolog toplevel.

FIle: my_db.pl

created(1676550097.280051).
assert(my_string("Hello, world!")).

The second part of the example run of corrected code using SWI-Prolog.

?- [example].
The stored string is: Hello, world!
true.

SWI-Prolog Foreign Language Interface (Ubuntu)

Prompt

Create an SWI-Prolog foreign language example Ubuntu OS. Include C code, SWI-Prolog predicate, how to compile code, run predicate and explain details.

ChatGPT Completion

Sure, here’s an example of using SWI-Prolog’s foreign language interface to call a C function on Ubuntu OS:

Create a C file called hello.c with the following contents:

#include <stdio.h>
#include <SWI-Prolog.h>

static foreign_t pl_hello(term_t arg) {
    char *name;
    if ( PL_get_atom_chars(arg, &name) )
        printf("Hello, %s!\n", name);
    PL_succeed;
}

install_t install() {
    PL_register_foreign("hello", 1, pl_hello, 0);
}

This defines a C function called pl_hello that takes a Prolog term as an argument and prints out a greeting. We also define an install function that registers the pl_hello function with SWI-Prolog.

Compile the C code into a shared library using the following command:

gcc -shared -o hello.so -fPIC hello.c `pkg-config --cflags --libs swipl`

This should create a file called hello.so in the current directory.

Open up SWI-Prolog in the terminal by typing swipl.

Load the shared library using the following command:

?- use_foreign_library('hello.so').

This should load the hello.so shared library into SWI-Prolog.

Now you can call the hello predicate from within SWI-Prolog:

?- hello('world').
Hello, world!
true.

The hello predicate takes one argument, which should be an atom, and calls the pl_hello function defined in the hello.c file.

Explanation:

The hello.c file defines a foreign language function called pl_hello that can be called from SWI-Prolog using the hello predicate. This function takes one argument, which should be a Prolog term. In this example, we expect the argument to be an atom (a string of characters), so we use the PL_get_atom_chars function to extract the character string from the Prolog term. We then print out a greeting using the printf function. Finally, we call PL_succeed to indicate that the function executed successfully.

The install function is called when the shared library is loaded, and it registers the pl_hello function with SWI-Prolog using the PL_register_foreign function.

To compile the C code into a shared library, we use the gcc command with the -shared flag to specify that we want to create a shared library, the -o flag to specify the output file name, and the -fPIC flag to generate position-independent code. We also use pkg-config to find the SWI-Prolog library and include the necessary header files and libraries.

In SWI-Prolog, we use the use_foreign_library predicate to load the shared library into the Prolog environment. We can then call the hello predicate with an atom argument to execute the pl_hello function and print out a greeting.

Prompt

gcc -shared -o hello.so -fPIC hello.c `pkg-config --cflags --libs swipl`

ChatGPT Completion

Sure, let me explain the command:

gcc is the GNU Compiler Collection, a compiler for C and other programming languages.
-shared specifies that we want to create a shared library instead of an executable.
-o hello.so specifies the name of the output file we want to create. In this case, we want to create a shared library called hello.so.
-fPIC stands for Position Independent Code, which is necessary when creating a shared library.
hello.c is the name of the C source file that we want to compile.
pkg-config --cflags --libs swipl is a command that generates the necessary compiler flags and linker options for SWI-Prolog, using the pkg-config utility. The --cflags option generates the necessary compiler flags, and the --libs option generates the necessary linker options. swipl is the name of the SWI-Prolog library that we want to link against.
Putting it all together, the gcc command compiles the hello.c file into a shared library called hello.so, using the necessary compiler flags and linker options to link against the SWI-Prolog library.

Notes:
pckg-config (Wikipedia)

groot@Galaxy:~$ pkg-config --cflags --libs swipl
-I/usr/local/lib/swipl/include -L/usr/local/lib/swipl/lib/x86_64-linux -lswipl

Convert HTML to HTML//1 DCG

SWI-Prolog can produce output for the web in the form of an HTML document using library(http/html_write). Given HTML, ChatGPT can generate the equivalent DCG to use with html//1.

Prompt

Convert following HTML to SWI-Prolog html//1 DCG named time_body

ChatGPT Completion

Here’s the SWI-Prolog DCG code for the HTML snippet:

time_body -->
    html(body([],
    [
        pre([style('word-wrap: break-word; white-space: pre-wrap;')],
            [
                '05 Example',
                br([]),
                'Time: Placeholder for now.'
            ])
    ])).

You can use the above code as a DCG rule in your SWI-Prolog program and call it with phrase(time_body, Html) to generate the corresponding HTML markup in Html variable.


This is not from the completion.

This can be then used as follows

File: server.pl

:- module(server,[]).

:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).
:- use_module(library(http/html_write)).

:- initialization(start_server).

:- http_handler(root(.), time_page, []).

time_page(_) :-
	reply_html_page(
	    title('Example'),
	    \time_body).

time_body -->
    html(body([],
    [
        pre([style('word-wrap: break-word; white-space: pre-wrap;')],
            [
                '05 Example',
                br([]),
                'Time: Placeholder for now.'
            ])
    ])).

start_server :-
    http_server(http_dispatch, [port(8080)]).

Example run using SWI-Prolog

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

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

?- [server].
% Started server at http://localhost:8080/
true.

Then using Internet browser
URL: http://localhost:8080/

05 Example

Time: Placeholder for now.

Convert format/2 to debug/3

Most programmers are familiar with the practice of debugging by inserting print statements, e.g. format/2 predicate in Prolog, to display variable values or indicate the execution of a code section. However, once the debugging is done, these print statements need to be manually removed. A more effective approach is to convert these statements into a more flexible and useful form, such as disabling them in an optimized build, outputting them only under certain conditions, or logging them to a file.

ChatGPT can convert Prolog code that uses format/2 predicates to utilize SWI-Prolog’s debug/3 predicates.

Prompt

Convert format/2 predicates below to debug/3 predicate, for the debug/3 topic arguement use http(open)

open_socket(Address, StreamPair, Options) :-
    format('http_open: Connecting to ~p ...', [Address]),
    tcp_connect(Address, StreamPair, Options),
    stream_pair(StreamPair, In, Out),
    format('\tok ~p ---> ~p', [In, Out]),
    set_stream(In, record_position(false)),
    (   option(timeout(Timeout), Options)
    ->  set_stream(In, timeout(Timeout))
    ;   true
    ).

ChatGPT Completion

Here’s the converted code with the debug/3 predicate:

open_socket(Address, StreamPair, Options) :-
    debug(http(open), 'Connecting to ~p ...', [Address]),
    tcp_connect(Address, StreamPair, Options),
    stream_pair(StreamPair, In, Out),
    debug(http(open), 'ok ~p ---> ~p', [In, Out]),
    set_stream(In, record_position(false)),
    (   option(timeout(Timeout), Options)
    ->  set_stream(In, timeout(Timeout))
    ;   true
    ).

In this code, the debug/3 predicate is used instead of the format/2 predicate. The first argument of debug/3 is the topic, which is set to http(open) in this case. The second argument is the message to be printed, which is the same as the string used in the format/2 predicate. The third argument is the list of values to be inserted into the message string, which is also the same as the list used in the format/2 predicate.

Check term is a bit flag

With llibrary(persistency) needed to add a type for bit flag.

Prompt

Write SWI-Prolog predicate error:has_type/2 to check if a term is a flag. A flag is an integer value that has only one bit set or all bits set to zero.

ChatGPT Completion (ChatGPT Mar 14 Version)

Here’s an implementation of the error:has_type/2 predicate in SWI-Prolog that checks if a given term is a flag:

error:has_type(Term, flag) :-
    integer(Term),
    (Term =:= 0 ; popcount(Term, 1)).

This predicate first checks that Term is an integer using the integer/1 predicate. Then it uses the =:=/2 operator to check if Term is equal to 0, which means that all bits are set to zero. If Term is not equal to 0, it checks if the number of bits set to 1 in Term is equal to 1 using the popcount/2 predicate.

Note that popcount/2 is a built-in SWI-Prolog predicate that counts the number of bits set to 1 in an integer.

popcount/2 was unexpected, in checking it is really a function (used with is/2) popcount/1.

The correct code is

:- multifile error:has_type/2.

error:has_type(flag_bit,Term) :-
    integer(Term),
    (
        Term =:= 0
    ;
        Count is popcount(Term),
        Count =:= 1
    ).

Notes

  • The arguments were in the wrong oder, corrected order, e.g. (Term, flag) became (flag,Term)
  • Changed the name from flag to flag_bit as flag is typically used to refer to an integer value that holds more than one bit flag.
  • This directive is needed, :- multifile error:has_type/2.