# ChatGPT prompts - SWI-Prolog (1)

**URL:** <https://swi-prolog.discourse.group/t/chatgpt-prompts-swi-prolog-1/6259>\
**Category:** Wiki\
**Tags:** chatgpt\
**Created:** [February 17, 2023, 8:23am UTC](https://swi-prolog.discourse.group/t/chatgpt-prompts-swi-prolog-1/6259 "2023-02-17T08:23:09Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [February 17, 2023, 8:23am UTC](https://swi-prolog.discourse.group/t/chatgpt-prompts-swi-prolog-1/6259/1 "2023-02-17T08:23:09Z")

</div>

## Installation

Prompt

> How to install SWI-Prolog on Windows

ChatGPT Completion

> To install SWI-Prolog on Windows, follow these steps:
> 
> 1. Download the SWI-Prolog installation file for Windows from the official website ([SWI-Prolog downloads](https://www.SWI-Prolog.org/Download.html))
> 2. Double-click on the installation file to start the setup process.
> 3. Follow the on-screen instructions to complete the installation.
> 4. Add the SWI-Prolog bin folder to the PATH environment variable to make it accessible from the command line.
> 5. Example: If you installed SWI-Prolog in C:\Program Files\swipl, add C:\Program Files\swipl\bin to your PATH environment variable.
> 
> You can now start the SWI-Prolog interpreter by opening the Command Prompt and typing swipl.

If you search for how to install SWI-Prolog on Windows you may find some YouTube videos, using [winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/) and other sets of instructions. The official place to find the SWI-Prolog download for the installer on Windows is correctly given by ChatGPT, [SWI-Prolog downloads](https://www.swi-prolog.org/Download.html).

For more detailed instructions with screen shots of steps see:  
[Install SWI-Prolog development version on Windows 10](https://swi-prolog.discourse.group/t/install-swi-prolog-development-version-on-windows-10/1131)

## Constraints - Finite Domain

Prompt

> Create SWI-Prolog Prolog code to solve the 8 queens problem using finite domain constraints.

ChatGPT Completion

> Here is an example SWI-Prolog code that solves the 8 queens problem using finite domain constraints:

```prolog
:- use_module(library(clpfd)).

% This predicate finds a solution to the 8 queens problem and prints it.
queens :-
    % Define the domain of the variables.
    length(Queens, 8),
    Queens ins 1..8,
    % Define the constraints.
    all_different(Queens),
    diagonal_constraints(Queens),
    % Use labeling to find a solution.
    labeling([], Queens),
    % Print the solution.
    print_solution(Queens).

% This predicate defines the diagonal constraints.
diagonal_constraints([]).
diagonal_constraints([Q|Queens]) :-
    diagonal_constraints(Queens, Q, 1),
    diagonal_constraints(Queens).

diagonal_constraints([], _, _).
diagonal_constraints([Q|Queens], Q0, D0) :-
    D is abs(Q0 - Q),
    D \= D0,
    D1 is D0 + 1,
    diagonal_constraints(Queens, Q0, D1).

% This predicate prints a solution to the 8 queens problem.
print_solution([]).
print_solution([Q|Queens]) :-
    print_row(Q),
    print_solution(Queens).

print_row(Q) :-
    Length is 8 - Q,
    write('|'),
    print_spaces(Length),
    write('Q'),
    print_spaces(Q - 1),
    write('|'),
    nl.

print_spaces(0).
print_spaces(N) :-
    write(' '),
    N1 is N - 1,
    print_spaces(N1).

```

> To use this code, simply load it into SWI-Prolog and call the `queens` predicate:

```prolog
?- queens.
| Q|
|Q 8 |
| Q 6 |
| Q 1 |
| Q 5 |
| Q 3|
| Q 2|
| Q7|
true .

```

> This will find a solution to the 8 queens problem and print it. The solution will consist of a list of 8 integers, each representing the row of the queen in the corresponding column. The output is formatted to display the board with the queen positions using ASCII characters.

The code does not result in any warnings or errors with make/0 on SWI-Prolog, it does result in an error when run.

```prolog
?- queens.
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [13] _27268 is abs(_27278-_27280)

```

For the more general problem of queens on a square board see:  
[clpfd - Understanding CLP(FD) Prolog code of N-queens problem - Stack Overflow](https://stackoverflow.com/a/53412988/1243762)

## Data conversion to/from JSON

In programming, you often need to convert data to or from other formats for use with other software. One of the most common formats for interchanging data is JSON. One of the easiest ways to get ChatGPT to work with a table of data is to have it generate a small set of data and instruct it to limit the size, often by specifying a number.

Prompt

> Generate data about the first 10 U.S. presidents as Prolog facts.

```prolog
% Facts about the first 10 U.S. Presidents
president(1, george_washington, 1789, 1797).
president(2, john_adams, 1797, 1801).
president(3, thomas_jefferson, 1801, 1809).
president(4, james_madison, 1809, 1817).
president(5, james_monroe, 1817, 1825).
president(6, john_q_adams, 1825, 1829).
president(7, andrew_jackson, 1829, 1837).
president(8, martin_van_buren, 1837, 1841).
president(9, william_henry_harrison, 1841).
president(10, john_tyler, 1841, 1845).

```

Prompt

> For SWI-Prolog create a Prolog predicate to convert president data to JSON. Use SWI-Prolog libraries as needed.

ChatGPT Completion

> Here is a Prolog predicate that converts the Prolog facts about the first 10 U.S. presidents to JSON using the SWI-Prolog libraries:

```prolog
:- use_module(library(http/json)).

presidents_json(PresidentsJson) :-
    findall(President, president(President), Presidents),
    maplist(president_json, Presidents, PresidentsJsonList),
    dict_create(PresidentsDict, presidents, PresidentsJsonList),
    json_write_dict(current_output, PresidentsDict, [indent(2)]).

president_json(president(Number, Name, StartYear, EndYear), PresidentJson) :-
    dict_create(PresidentDict, president, [
        number-Number,
        name-Name,
        start_year-StartYear,
        end_year-EndYear
    ]),
    PresidentJson = PresidentDict.

```

> The `presidents_json/1` predicate takes one argument, `PresidentsJson`, which is the JSON representation of the first 10 U.S. presidents. The predicate uses the `findall/3` built-in predicate to gather a list of all the `president` facts, then maps over that list using the `president_json/2` predicate to convert each fact to a JSON object. Finally, the `dict_create/3` predicate is used to create a dictionary with the list of JSON objects, which is then written to the current output as formatted JSON using the `json_write_dict/3` predicate.
> 
> The `president_json/2` predicate takes a `president/4` fact and converts it to a JSON object. It uses the `dict_create/3` predicate to create a dictionary with the relevant fields for the president, then creates a new dictionary with the `president` key and the dictionary of fields. This new dictionary is then unified with the `PresidentJson` argument.

The code results in a warning with [make/0](https://www.swi-prolog.org/pldoc/doc_for?object=make/0) on [SWI-Prolog](https://www.swi-prolog.org/pldoc/doc_for?object=manual).

```prolog
Warning: Singleton variables: [PresidentsJson]

```

It results in an error when run.

```prolog
?- presidents_json(_).
ERROR: Type error: `key-value' expected, found `president{end_year:1797,name:george_washington,number:1,start_year:1789}' (a dict)

```

Here is correct code.

```prolog
presidents_json :-
  findall(president(Number, Name, StartYear, EndYear), president(Number, Name, StartYear, EndYear), Presidents),
  maplist(president_json, Presidents, PresidentsJsonList),
  dict_create(PresidentsDict, presidents, PresidentsJsonList),
  json_write_dict(current_output, PresidentsDict, [indent(2)]).

president_json(president(Number, Name, StartYear, EndYear), Name-PresidentDict) :-
  dict_create(PresidentDict, president, [
      number-Number,
      name-Name,
      start_year-StartYear,
      end_year-EndYear
  ]).

```

The first change is make the Goal and Template arguments for finall/3 the same,

```prolog
findall(president(Number, Name, StartYear, EndYear), president(Number, Name, StartYear, EndYear), Presidents)

```

The second change is to change the result of president\_json/2 to return a key-value instead of a dict.

The third change is to just remove the argument for presidents\_json/1 as it is not used.

Example run of corrected code on SWI-Prolog.

```prolog
?- example:presidents_json.
{
    "andrew_jackson": {
      "end_year":1837,
      "name":"andrew_jackson",
      "number":7,
      "start_year":1829
    },
    "george_washington": {
      "end_year":1797,
      "name":"george_washington",
      "number":1,
      "start_year":1789
    },
    "james_madison": {
      "end_year":1817,
      "name":"james_madison",
      "number":4,
      "start_year":1809
    },
    "james_monroe": {
      "end_year":1825,
      "name":"james_monroe",
      "number":5,
      "start_year":1817
    },
    "john_adams": {
      "end_year":1801,
      "name":"john_adams",
      "number":2,
      "start_year":1797
    },
    "john_quincy_adams": {
      "end_year":1829,
      "name":"john_quincy_adams",
      "number":6,
      "start_year":1825
    },
    "john_tyler": {
      "end_year":1845,
      "name":"john_tyler",
      "number":10,
      "start_year":1841
    },
    "martin_van_buren": {
      "end_year":1841,
      "name":"martin_van_buren",
      "number":8,
      "start_year":1837
    },
    "thomas_jefferson": {
      "end_year":1809,
      "name":"thomas_jefferson",
      "number":3,
      "start_year":1801
    },
    "william_henry_harrison": {
      "end_year":1841,
      "name":"william_henry_harrison",
      "number":9,
      "start_year":1841
    }
  }
true.

```

This verifies as valid JSON at [https://jsonlint.com/](https://jsonlint.com/)

Prompt

> For SWI-Prolog create a Prolog predicate to convert president data as JSON to Prolog facts. Use SWI-Prolog libraries as needed.

ChatGPT Completion

> Here is a Prolog predicate that converts the JSON data to Prolog facts using the SWI-Prolog libraries:

```prolog
:- use_module(library(http/json)).

presidents_from_json(Presidents) :-
    json_file('presidents.json', JsonData),
    dict_pairs(JsonData, presidents, Pairs),
    maplist(president_from_json, Pairs, Presidents).

president_from_json(Name-PresDict, president(Number, Name, StartYear, EndYear)) :-
    dict_pairs(PresDict, _, [
        number-Number,
        start_year-StartYear,
        end_year-EndYear
    ]).

```

> The `presidents_from_json/1` predicate reads the JSON data from a file using the `json_file/2` predicate, then converts the dictionary of presidents into a list of key-value pairs using the `dict_pairs/3` predicate. It then maps over the pairs using the `president_from_json/2` predicate to convert each key-value pair into a `president/4` fact.
> 
> The `president_from_json/2` predicate takes a key-value pair from the JSON data and converts it into a `president/4` fact. It first extracts the name of the president from the key, then extracts the relevant fields from the value dictionary using the `dict_pairs/3` predicate. Finally, it unifies the extracted fields with a new `president/4` fact.

The ChatGPT code has design flaws.

Here is similar working code.

```prolog
json(Json) :-
    Json =
'{
    "andrew_jackson": {
      "end_year":1837,
      "name":"andrew_jackson",
      "number":7,
      "start_year":1829
    },
    "george_washington": {
      "end_year":1797,
      "name":"george_washington",
      "number":1,
      "start_year":1789
    },
    "james_madison": {
      "end_year":1817,
      "name":"james_madison",
      "number":4,
      "start_year":1809
    },
    "james_monroe": {
      "end_year":1825,
      "name":"james_monroe",
      "number":5,
      "start_year":1817
    },
    "john_adams": {
      "end_year":1801,
      "name":"john_adams",
      "number":2,
      "start_year":1797
    },
    "john_quincy_adams": {
      "end_year":1829,
      "name":"john_quincy_adams",
      "number":6,
      "start_year":1825
    },
    "john_tyler": {
      "end_year":1845,
      "name":"john_tyler",
      "number":10,
      "start_year":1841
    },
    "martin_van_buren": {
      "end_year":1841,
      "name":"martin_van_buren",
      "number":8,
      "start_year":1837
    },
    "thomas_jefferson": {
      "end_year":1809,
      "name":"thomas_jefferson",
      "number":3,
      "start_year":1801
    },
    "william_henry_harrison": {
      "end_year":1841,
      "name":"william_henry_harrison",
      "number":9,
      "start_year":1841
    }
  }'.

:- dynamic president/4.

presidents_from_json :-
    json(Json_string),
    open_string(Json_string,Stream),
    json_read_dict(Stream, Presidents_dict),
    dict_pairs(Presidents_dict,_,Pairs),
    pairs_values(Pairs,Values),
    dicts_to_compounds(Values, [number,name,start_year,end_year], dict_fill(null), Compounds),
    maplist(assert_new_functor(president),Compounds).

assert_new_functor(Functor,Compound0) :-
    compound_name_arguments(Compound0,_,Arguments),
    compound_name_arguments(Compound,Functor,Arguments),
    (
        Compound, !
    ;
        assertz(Compound)
    ).

```

Example run using SWI-Prolog

```prolog
?- presidents_from_json.
true.

?- listing(M:president/4).
:- dynamic president/4.

president(7, "andrew_jackson", 1829, 1837).
president(1, "george_washington", 1789, 1797).
president(4, "james_madison", 1809, 1817).
president(5, "james_monroe", 1817, 1825).
president(2, "john_adams", 1797, 1801).
president(6, "john_quincy_adams", 1825, 1829).
president(10, "john_tyler", 1841, 1845).
president(8, "martin_van_buren", 1837, 1841).
president(3, "thomas_jefferson", 1801, 1809).
president(9, "william_henry_harrison", 1841, 1841).

```

## Guess a number

Can ChatGPT generate code that prompts a user for input.

Prompt

> In Prolog create a program to allow a user to guess a number by prompting for a number and then replying higher or lower and repeating until the number is found.

ChatGPT Completion

```prolog
%% Main query to generate guesses
guess(N):-
    write('guess a number: '),
    read(Guess),    
    (
        Guess == N
        -> write('You guessed correctly!');
        (
            Guess > N
            -> write('Lower!'),
            nl,
            guess(N);
            write('Higher!'),
            nl,
            guess(N)
        )
    ).

```

Prompt

> Demonstrate this code.

ChatGPT Completion

```prolog
?- guess(7).
guess a number: 5
Higher!
guess a number: 9
Lower!
guess a number: 7
You guessed correctly!

```

Prompt

> Explain the code.

ChatGPT Completion

> This code allows a user to guess a number by prompting for a number and then replying higher or lower and repeating until the number is found. The code starts by setting up the main query, guess(N), which prompts the user to guess a number and reads the user’s input. If the user’s input is equal to N (the number to guess), then the user is told that they guessed correctly. If the user’s input is greater than N, then the user is told to guess lower and the query is repeated. If the user’s input is less than N, then the user is told to guess higher and the query is repeated. The query repeats until the user guesses correctly.

Example run using SWI-Prolog

```prolog
?- guess(23).
guess a number: 10.
Higher!
guess a number: |: 20.
Higher!
guess a number: |: 30.
Lower!
guess a number: |: 24.
Lower!
guess a number: |: 22.
Higher!
guess a number: |: 23.
You guessed correctly!
true.

```

Notice that each input number ends with a period. This is because the Prolog predicate read/1 expects a Prolog term and all Prolog terms end with a period. A better solution would use read\_string/5. See if you can use Prompt Engineering to get ChatGPT to create code for the guessing game using read\_string/5.

## Prolog modules

Prompt

> In Prolog create two files each using use\_module. One module is a list of 5 Greek gods and their father. The other module is an ancestor predicate. Demonstrate and explain the code.

ChatGPT Completion

> Module 1: gods.pl

```prolog
% gods.pl
% This module contains a list of five Greek gods and their father

:- module(gods, [god/2]).

god(zeus, kronos).
god(hera, kronos).
god(poseidon, kronos).
god(hades, kronos).
god(ares, zeus).

```

> Module 2: ancestor.pl

```prolog
% ancestor.pl
% This module contains an ancestor predicate

:- module(ancestor, [ancestor/2]).

:- use_module(gods).

ancestor(X, Y) :-
    god(X, Y).
ancestor(X, Y) :-
    god(X, Z),
    ancestor(Z, Y).

```

> The first module, gods.pl, defines a module gods that contains a predicate god/2 that takes two arguments, X and Y, representing a Greek god and its father. The module contains facts that define the five gods given and their father.
> 
> The second module, ancestor.pl, defines a module ancestor that contains a single predicate ancestor

For some reason it did not demonstrate the code so asked separately.

Prompt

> Demonstrate the code.

ChatGPT Completion

```prolog
?- use_module(gods).
true.

?- use_module(ancestor).
true.

?- god(X, kronos).
X = zeus ;
X = hera ;
X = poseidon ;
X = hades ;
false.

?- ancestor(X, kronos).
X = zeus ;
X = hera ;
X = poseidon ;
X = hades ;
X = ares ;
false.

```

## Tabling

Prompt

> Create a Prolog predicate to generate Fibonacci numbers using tabling.

ChatGPT Completion

> Here’s an implementation of a Prolog predicate to generate the nth Fibonacci number using tabling:

```prolog
:- table fib/2.

fib(0, 0).
fib(1, 1).
fib(N, F) :-
   N > 1,
   N1 is N - 1,
   N2 is N - 2,
   fib(N1, F1),
   fib(N2, F2),
   F is F1 + F2.

```

> In this implementation, the `:- table fib/2.` directive at the beginning of the code tells Prolog to use tabling for the `fib/2` predicate. Tabling is a mechanism for memoization in Prolog that caches the results of predicate calls to avoid redundant computations.
> 
> The rest of the implementation is similar to the previous implementation, defining two base cases `fib(0, 0)` and `fib(1, 1)`, and a recursive case `fib(N, F)` to calculate the Nth Fibonacci number. The recursive case uses the Prolog built-in `is/2` predicate to evaluate expressions and unify their values with variables. The predicate calculates the (N-1)th and (N-2)th Fibonacci numbers first and then adds them to get the Nth Fibonacci number.
> 
> With tabling, the results of each calculation are stored in a table, so if the same calculation is performed again in the future, the result can be retrieved from the table instead of re-computing it. This greatly improves the efficiency of the `fib/2` predicate, especially for larger values of N.

Example run using SWI-Prolog

```prolog
?- maplist(fib,[0,1,2,3,4,5,6,7,8,9,10],F).
F = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].

```

## Collections

Prompt

> Create a Prolog facts for eight Greek gods. For each god include three properties.

ChatGPT Completion

```prolog
god(zeus, king, lightning).
god(hera, queen, marriage).
god(poseidon, sea, earthquakes).
god(demeter, harvest, agriculture).
god(ares, war, courage).
god(aphrodite, love, beauty).
god(athena, wisdom, war).
god(apollo, music, archery).
god(artemis, hunt, wild_animals).

```

> In the above example, each fact is written as “god(Name, Property1, Property2)” where `Name` is the name of the god, `Property1` and `Property2` are two of the three properties associated with that god.

### findall

Prompt

> For the Prolog god facts use the findall predicated to collect the name.

ChatGPT Completion

> Here is an example of using the `findall/3` predicate to collect the names of the gods:

```prolog
all_gods(Gods) :-
    findall(Name, god(Name, _, _), Gods).

```

> In the above code, the `findall/3` predicate collects all the names of the gods into a list `Gods` . The first argument to `findall/3` is the template for the elements to be collected, in this case `Name` . The second argument is a goal that defines the elements to be collected, in this case `god(Name, _, _)` . The third argument is the list in which the collected elements are stored, in this case `Gods` . The predicate `all_gods/1` can be used to obtain the list of all the gods, for example:

```prolog
?- all_gods(Gods).
Gods = [zeus, hera, poseidon, demeter, ares, aphrodite, athena, apollo, artemis].

```

### setof

Prompt

> For the Prolog god facts use the setof predicated to collect the name.

ChatGPT Completion

> Here is an example of using the `setof/3` predicate to collect the names of the gods:

```prolog
all_gods(Gods) :-
    setof(Name, god(Name, _, _), Gods).

```

> In the above code, the `setof/3` predicate collects all the names of the gods into a list `Gods` . The first argument to `setof/3` is the template for the elements to be collected, in this case `Name` . The second argument is a goal that defines the elements to be collected, in this case `god(Name, _, _)` . The third argument is the list in which the collected elements are stored, in this case `Gods` . The predicate `all_gods/1` can be used to obtain the list of all the gods, for example:

```prolog
?- all_gods(Gods).
Gods = [apollo, ares, artemis, aphrodite, athena, demeter, hera, poseidon, zeus].

```

> Note that `setof/3` returns the collected elements in sorted order, so the list of gods returned by the above code will be sorted alphabetically.

setof/3 is typically used to select all facts sorted. Because setof/3 is used incorrectly the result is different.

Example run using SWI-Prolog

```prolog
?- all_gods(Gods).
Gods = [demeter] ;
Gods = [artemis] ;
Gods = [zeus] ;
Gods = [aphrodite] ;
Gods = [apollo] ;
Gods = [hera] ;
Gods = [poseidon] ;
Gods = [ares] ;
Gods = [athena]

```

Here is the corrected code.

```prolog
all_gods(Gods) :-
    setof(Name, [A,B]^god(Name, A, B), Gods).

```

For details on how to use ^/2 see this [reply](https://swi-prolog.discourse.group/t/programming-cooperation/5623/8).

Example run with SWI-Prolog

```prolog
?- all_gods(Gods).
Gods = [aphrodite, apollo, ares, artemis, athena, demeter, hera, poseidon, zeus].

```

### maplist

Prompt

> Create a Prolog maplist predicate that extracts the first two parameters of a functor and returns them as the first two arguments of a functor named edge.

ChatGPT Completion

> Here’s a Prolog maplist predicate that extracts the first two parameters of a functor and returns them as the first two arguments of a functor named `edge`:

```prolog
maplist_edge(List,Result) :-
    maplist(extract_edge, List, Result).

extract_edge(Func, edge(First, Second)) :-
    Func =.. [_|Args],
    [First,Second|_] = Args.

```

> The `maplist_edge/2` predicate uses the `maplist/2` predicate to apply the `extract_edge/2` predicate to each element of the list `List`. The `extract_edge/2` predicate uses `=..` (univ operator) to extract the arguments of the input functor `Func` and then uses pattern matching to extract the first two elements of the argument list as `First` and `Second`.

## Predicate signature

Prompt

> Show a Prolog predicate with a comment containing the predicate signature.

ChatGPT Completion

> Here’s an example Prolog predicate for finding the sum of two numbers:

```prolog
% sum(+A:integer, +B:integer, -C:integer) is det.
sum(A, B, C) :-
   C is A + B.

```

> The predicate signature is as follows:

```prolog
sum(+A:integer, +B:integer, -C:integer) is det.

```

> This means that `sum/3` is a deterministic predicate that takes two integers `A` and `B` as input (indicated by the `+` sign) and returns the sum `C` of the two numbers as output (indicated by the `-` sign).

Note: I asked the question the first time and it did not give a correct answer so used thumbs down giving a correct example of a predicate signature. The above is the second time I asked. It also used a different predicate than the first, was really nice to see that it is learning quickly.

Also the [SWI-Prolog](https://www.swi-prolog.org/pldoc/doc_for?object=manual) documentation for [sum/3](https://www.swi-prolog.org/pldoc/doc_for?object=sum/3) is

> **sum** (+Vars, +Rel, ?Expr)

notice that the last mode is not `-` but `?`.

## HTTP server - Hello World

Prompt

> Create a [SWI-Prolog](https://www.swi-prolog.org/pldoc/doc_for?object=manual) predicate to serve a Hello World page. Use [initialization/1](https://www.swi-prolog.org/pldoc/doc_for?object=initialization/1).

ChatGPT Completion

> Here is an example of a [SWI-Prolog](https://www.swi-prolog.org/pldoc/doc_for?object=manual) predicate to serve a “Hello World” page using the `http_handler/3` predicate and the `initialization/1` directive:

```prolog
:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).

:- http_handler(root(hello), say_hi, []).

say_hi(Request) :-
    format('Content-type: text/plain~n~n'),
    format('Hello World!~n').

:- initialization(start_server).

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

```

> The `http_handler/3` predicate sets up a handler for the URL path `/hello`, which is handled by the `say_hi/1` predicate. The `say_hi/1` predicate outputs the text “Hello World!” in plain text format. The `initialization/1` directive calls the `start_server/0` predicate when the program is loaded, which starts the HTTP server on port 8080 using `http_server/2`.

Prompt

> How would I start the server and view the page?

ChatGPT Completion

> You can start the server by running the following command in the [SWI-Prolog](https://www.swi-prolog.org/pldoc/doc_for?object=manual) console:

```prolog
?- [file_name].

```

> where `file_name` is the name of the file containing the above code. The server should then start and be ready to receive requests.
> 
> To view the “Hello World” page, you can open a web browser and go to the following URL:

```prolog
http://localhost:8080/hello

```

> This will send a request to the server running on `localhost` on port `8080` for the `/hello` path, which will be handled by the `say_hi/1` predicate and return the “Hello World!” message.

## HTTP Server - Web Socket Echo

Prompt

> Show code that demonstrates echo using web sockets, do the server using SWI-Prolog in a file named server.pl and the client using HTML in a file named index.html the the JavaScript in a file named echo.js.

ChatGPT Completion

> Here is an example code for implementing a simple echo server using web sockets in SWI-Prolog and a client in HTML and JavaScript:
> 
> server.pl:

```prolog
:- use_module(library(http/websocket)).
:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).

:- http_handler(root(.), http_upgrade_to_websocket(echo), []).
:- http_handler(root(echo), echo, []).

server(Port) :-
    http_server(http_dispatch, [port(Port)]).

echo(WebSocket) :-
    ws_receive(WebSocket, Message),
    ( Message.opcode == close
    -> true
    ; ws_send(WebSocket, Message.data, Message.opcode),
        echo(WebSocket)
    ).

```

> index.html:

```html
<!DOCTYPE html>
<html>
<head>
    <title>Echo Client</title>
</head>
<body>
    <input type="text" id="input">
    <button onclick="send()">Send</button>
    <br>
    <textarea id="output" cols="50" rows="10"></textarea>

    <script src="echo.js"></script>
</body>
</html>

```

> echo.js:

```javascript
var ws = new WebSocket("ws://localhost:8080/echo");

ws.onopen = function(event) {
    console.log("WebSocket connection opened.");
};

ws.onmessage = function(event) {
    document.getElementById("output").value += event.data + "\n";
};

ws.onclose = function(event) {
    console.log("WebSocket connection closed.");
};

function send() {
    var input = document.getElementById("input").value;
    ws.send(input);
    document.getElementById("input").value = "";
}

```

> This code sets up a simple echo server that listens for WebSocket connections on port 8080. The server simply echoes back any messages it receives from a client. The client is an HTML page that includes a text input and a button to send messages to the server. The JavaScript code creates a WebSocket connection to the server and sends any input from the user to the server. When the client receives a message from the server, it appends the message to a text area on the page.

This is close but needs just a few changes to make it work.

server.pl

```prolog
:- use_module(library(http/websocket)).
:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).

:- initialization
    http_server(http_dispatch, [port(8000)]).

:- http_handler(root(.), http_reply_file('index.html', []), []).
:- http_handler(root('echo.js'), http_reply_file('echo.js', []), []).
:- http_handler(
        root(echo),
        http_upgrade_to_websocket(echo, []),
        [spawn([])]
    ).

echo(WebSocket) :-
    ws_receive(WebSocket, Message, [format(json)]),
    (
        Message.opcode == close
    ->
        true
    ;
        ws_send(WebSocket, Message),
        echo(WebSocket)
    ).

```

index.html

```html
<!DOCTYPE html>
<html>
<head>
    <title>Echo Client</title>
</head>
<body>
    <input type="text" id="input">
    <button onclick="send()">Send</button>
    <br>
    <textarea id="output" cols="50" rows="10"></textarea>

    <script src="echo.js"></script>
</body>
</html>

```

echo.js

```javascript
var ws = new WebSocket("ws://" + window.location.host + "/echo");

ws.onopen = function(event) {
    console.log("WebSocket connection opened.");
};

ws.onmessage = function(event) {
  const payload = JSON.parse(event.data)
  document.getElementById("output").value += payload + "\n";
};

ws.onclose = function(event) {
    console.log("WebSocket connection closed.");
};

function send() {
    var input = document.getElementById("input").value;
    ws.send(JSON.stringify(input))
    document.getElementById("input").value = "";
}

```

Example run

```prolog
Welcome to SWI-Prolog (threaded, 64 bits, version 9.1.6)
...
?- working_directory(_,'C:/Users/Groot').
true.

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

?- 

```

Using Internet browser  
URL: [http://localhost:8000/](http://localhost:8000/)

 ![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/f/fedd1e35ec8682d40e2c617f8edb5e4ea1ce2aa5.png)

Enter text then press Send

 ![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/5/5befc1ae43ae4a38080b54108b939668d0ed3d90.png)

## Meta predicates

Getting ChatGPT to create this took more than 10 attempts at the prompt. Even gave up on giving ChatGPT the working code first and asking it to create a prompt. It just never seemed to know how to use [meta\_predicate](https://www.swi-prolog.org/pldoc/man?section=metapred) as a directive which is why the prompt is so specific about that.

Prompt

> Create two modules, the first module ‘indirection’ contains the predicate display\_list/1 with a goal argument. display\_list/1 is a meta\_predicate so a meta\_predicate directive needs to be used. The second module `examples` uses use\_module for the module ‘indirection’ and contains two predicates, nodes/1 that returns a list, [check/0](https://www.swi-prolog.org/pldoc/doc_for?object=check/0) that calls display\_list and passes the goal ‘nodes’. Put the code in a code block for readability.

ChatGPT Completion

```prolog
%Module 1 - indirection.pl
:- module(indirection, [display_list/1]).
:- meta_predicate display_list(0).

display_list(Goal) :-
  call(Goal, List),
  write(List).

%Module 2 - examples.pl
:- module(examples, [check/0]).
:- use_module(indirection).

nodes(Nodes) :- Nodes = [1, 2, 3, 4, 5].

check :- display_list(nodes).

```

The first time a reply with working code the meta\_predicate was

`:- meta_predicate display_list(:).`

and this time it is

`:- meta_predicate display_list(0).`

both ways work.
