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:
- Start SWI-Prolog: Open a terminal or command prompt and start the SWI-Prolog interpreter by running the swipl command.
- 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).
- 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).
- 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
- Start a command prompt
- Use Windows
cd
batch command to change to the directory with the Prolog files. - 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
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
anddb_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.
my_string(value:atom).
should bemy_string(value:string).
- 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 inHtml
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 theformat/2
predicate. The first argument ofdebug/3
is the topic, which is set tohttp(open)
in this case. The second argument is the message to be printed, which is the same as the string used in theformat/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 theformat/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 theinteger/1
predicate. Then it uses the=:=/2
operator to check ifTerm
is equal to 0, which means that all bits are set to zero. IfTerm
is not equal to 0, it checks if the number of bits set to 1 inTerm
is equal to 1 using thepopcount/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
toflag_bit
asflag
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.