# Solving two consecutive dependent goals from command line

**URL:** <https://swi-prolog.discourse.group/t/solving-two-consecutive-dependent-goals-from-command-line/1270>\
**Category:** Help!\
**Created:** [September 17, 2019, 5:04pm UTC](https://swi-prolog.discourse.group/t/solving-two-consecutive-dependent-goals-from-command-line/1270 "2019-09-17T17:04:07Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![aminemarref](https://avatars.discourse-cdn.com/v4/letter/a/7feea3/32.png) [@aminemarref](https://swi-prolog.discourse.group/u/aminemarref)\
**Post date:** [September 17, 2019, 5:04pm UTC](https://swi-prolog.discourse.group/t/solving-two-consecutive-dependent-goals-from-command-line/1270/1 "2019-09-17T17:04:07Z")

</div>

Hello,

I want to be able to solve two Prolog goals `G1` and `G2` from command line as follows.  
`$ swipl -l program.pl -g G1 -g halt`  
`$ swipl -l program.pl -g G2 -g halt`

Goal `G2` can be solved independently of goal `G1`, or can use information available after solving `G1` (Solving `G2` takes potentially less time in this case). This question concerns the latter case.

My issue is how do I pass the knowledge-base state that is available once `G1` is solved in `$ swipl -l program.pl -g G1 -g halt`, to the evaluation of `G2` in `$ swipl -l program.pl -g G2 -g halt`?

I tried reading about saving states ([Understanding Saved States](https://www.swi-prolog.org/pldoc/man?section=saved-states)) but I honestly could not figure out how to do it.

Additionally, my program starts executing from the following point:

> :- main.  
> main:- %The program

I read in the mentioned section that I should use `initialization/1` or `initialization/2` instead of using the directive `:-` to fire up my program; but again, I do not know how this fits in everything.

My problem can be solved by allowing the user to enter the goals one after the other in one single execution of the program; but for automation purposes, this solution is not adequate for me.

So, how do I change the following two commands so that the knowledge base available at the end of solving `G1` is made available to solving `G2`.  
`$ swipl -l program.pl -g G1 -g halt`  
`$ swipl -l program.pl -g G2 -g halt`

Many thanks.

---

<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:** [September 17, 2019, 5:18pm UTC](https://swi-prolog.discourse.group/t/solving-two-consecutive-dependent-goals-from-command-line/1270/2 "2019-09-17T17:18:02Z")

</div>

I have not run any of your code or code specific to your question to test what I purpose.

In reading, [Understanding saved states](https://www.swi-prolog.org/pldoc/man?section=saved-states) it reads

> A SWI-Prolog _saved state_ is a _resource archive_ that contains the compiled program in a machine-independent format

which I am thinking saves the state of the code as well as any data. But from reading your problem you only want to pass the data out from one process and into another process. Also since the process are started from the command line and running consecutive, one process is not communicating with the other process so a requirement is that the state has to persist after a process dies/ends.

Have you looked at [library(persistence)](https://www.swi-prolog.org/pldoc/man?section=persistency) ?

While the example in the documentation is thin, I learned how to use it myself for a simple problem.

Here are some questions I asked a time ago [Trying to understand library(persistency)](https://swi-prolog.discourse.group/t/trying-to-understand-library-persistency/542) but it really will leave you with more questions than it helps. However if your data is simple then hopefully I should be able to help you if needed. 😃

---

<div class="post-metadata">

**Author:** ![PaulBrownMagic](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/paulbrownmagic/32/211_2.png) [@PaulBrownMagic](https://swi-prolog.discourse.group/u/PaulBrownMagic)\
**Post date:** [September 17, 2019, 6:01pm UTC](https://swi-prolog.discourse.group/t/solving-two-consecutive-dependent-goals-from-command-line/1270/3 "2019-09-17T18:01:23Z")

</div>

An alternative point of view is to consider this as a piping problem. Consider the following predicates in a file called `hello.pl`:

```prolog
who :-
    writeln("world.").

greet :-
    read(Who),
    write("Hello, "),
    write(Who),
    writeln("!").

```

Now you can run two sequential processes where the first outputs to STDOUT, and the second reads that from STDIN:

```prolog
:~$ swipl -g who -t halt -s hello.pl | swipl -g greet -t halt -s hello.pl
|: Hello, world!

```

* * *

Fun things to play with in this domain…

You can open the second instance of `swipl` and pipe into it right out of the first:

```prolog
who :-
    setup_call_cleanup(
    open(pipe('swipl -g greet -t halt -s hello.pl'), write, Stream),
        writeln(Stream, "world."),
        close(Stream)
    ).

```

So only needing to run:

```prolog
:~$ swipl -q -t who -s hello.pl

```

If you’d like to avoid appending fullstops on the output terms, [read\_line\_to\_string/2](https://www.swi-prolog.org/pldoc/man?section=readutil#read_line_to_string/2) is handy, but I can’t seem to get it to work with a piped in input stream for some reason?

---

<div class="post-metadata">

**Author:** ![swi](https://avatars.discourse-cdn.com/v4/letter/s/51bf81/32.png) [@swi](https://swi-prolog.discourse.group/u/swi)\
**Post date:** [September 17, 2019, 6:31pm UTC](https://swi-prolog.discourse.group/t/solving-two-consecutive-dependent-goals-from-command-line/1270/4 "2019-09-17T18:31:00Z")

</div>

> [@aminemarref](#):
>
> I want to be able to solve two Prolog goals `G1` and `G2` from command line as follows.  
> `$ swipl -l program.pl -g G1 -g halt`  
> `$ swipl -l program.pl -g G2 -g halt`

Perhaps I don’t understand something, but why don’t you just run:

```prolog
$ swipl -l program.pl -g "G1,G2" -g halt

```

---

<div class="post-metadata">

**Author:** ![aminemarref](https://avatars.discourse-cdn.com/v4/letter/a/7feea3/32.png) [@aminemarref](https://swi-prolog.discourse.group/u/aminemarref)\
**Post date:** [September 24, 2019, 9:39am UTC](https://swi-prolog.discourse.group/t/solving-two-consecutive-dependent-goals-from-command-line/1270/5 "2019-09-24T09:39:14Z")

</div>

The following is one use-case of my program.

- `User 1` uses the program to solve goal `G1`.
- `User 1` or another user `User 2` uses the program to solve goal `G2`.
- There is a way to determine that the solution of goal `G2` can benefit from the solution of goal `G1`.  
Any given user will not know of this background speed-up feature, so they cannot issue the command to solve the conjunction of goals `G1` and `G2`.  
In addition to this, solving `G1` might be expensive, so re-solving it in the conjunction is not feasible performance-wise.  
Perhaps my use of the word “consecutive” was misleading. What I meant was that I needed the knowledge base available at the end of solving one goal to be forwarded to the process of solving another goal.  
Maybe I will just write the knowledge base to a text file at the end of solving `G1` and reload it when solving `G2`.

---

<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:** [September 24, 2019, 10:53am UTC](https://swi-prolog.discourse.group/t/solving-two-consecutive-dependent-goals-from-command-line/1270/6 "2019-09-24T10:53:14Z")

</div>

> [@aminemarref](#):
>
> Maybe I will just write the knowledge base to a text file at the end of solving `G1` and reload it when solving `G2` .

Sorry to have to ask this again, but have you looked at [library(persistence)](https://www.swi-prolog.org/pldoc/man?section=persistency) ? 😃

If you did, I am curious as to why you can not use it for the example you have given.

---

<div class="post-metadata">

**Author:** ![aminemarref](https://avatars.discourse-cdn.com/v4/letter/a/7feea3/32.png) [@aminemarref](https://swi-prolog.discourse.group/u/aminemarref)\
**Post date:** [September 24, 2019, 3:54pm UTC](https://swi-prolog.discourse.group/t/solving-two-consecutive-dependent-goals-from-command-line/1270/7 "2019-09-24T15:54:30Z")

</div>

Yes I did 🙂 and I was a bit intimidated 🙂 I haven’t ruled out the use of persistence, I just could not get my mind around it.

Say I have the following program.

```prolog
:- dynamic entity/1.
program(Goal):-
    % Stuff
    assert(entity(A)),
    assert(entity(B)),
   % More stuff

```

How do I change this program using persistence so that it is possible to save the asserted entities at the end of a successful evaluation of `Goal`; and also consult any saved entities by a previous execution of the program? Something like:

```prolog
:- dynamic entity/1.
program(Goal):-
  % Are there entity/1 predicates stored from a previous execution, if yes, load them
  % Stuff
  assert(entity(A)),
  assert(entity(B)),
  % More stuff
  % Save the entities I have previously asserted

```

---

<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:** [September 24, 2019, 6:49pm UTC](https://swi-prolog.discourse.group/t/solving-two-consecutive-dependent-goals-from-command-line/1270/9 "2019-09-24T18:49:04Z")

</div>

First an example run to make sure it does what you expect.

Start SWI-Prolog to get [Toplevel](https://www.metalevel.at/prolog/concepts).

```prolog
Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.12)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit http://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- 

```

Since all of the code for this is in a single directory to make it easier to demonstrate,  
change the working directory to the location of the files. Obviously the directory name in the following example needs to be changed to what you are using.

```prolog
?- working_directory(_, 'C:/Users/Eric/Documents/Projects/Prolog/Persistence example/').
true.

```

Load the first program and run it

```prolog
?- consult("program_a.pl").
true.

?- program_1.
Starting saving 
Done 
true.

?- 

```

At this point the facts are still in file buffer but not written to the file. To get them saved to a file [halt/0](https://www.swi-prolog.org/pldoc/doc_for?object=halt/0) must be run. Running halt/0 will close the `Toplevel`

Doing this will create a file that contains the saved facts.

file: **data.journal**

```prolog
created(1569346573.8356802).
assert(entity("a")).
assert(entity("b")).

```

When I first saw the word `assert` in the file it confused me, but AFAIK that is how it works.

Start SWI-Prolog to get to `Topelvel`

```prolog
Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.12)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit http://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

?-

```

Since `Toplevel` was restarted, need to change the directory again.

```prolog
?- working_directory(_, 'C:/Users/Eric/Documents/Projects/Prolog/Persistence example/').
true.

```

Load the second program and run it.

```prolog
?- consult("program_b.pl").
true.

?- program_2.
Starting reading program 
"a"
"b"
false.

?- 

```

* * *

Details

**program\_a.pl**

```prolog
:- use_module('program_database.pl').

program_1 :-
    format('Starting saving ~n',[]),
    A = "a",
    B = "b",
    % Stuff
    %assert(entity(A)),
    (
        exists_entity(A)
    ;
        add_entity(A)
    ),
    %assert(entity(B)),
    (
        exists_entity(B)
    ;
        add_entity(B)
    ),
    % More stuff
    format('Done ~n',[]).

```

**program\_b.pl**

```prolog
:- use_module('program_database.pl').

program_2 :-
    format('Starting reading program ~n',[]),
    % Stuff
    write_entities.

write_entities :-
    facts:entity(A),
    write_canonical(A),nl,
    fail.

```

The module that implements the predicates `exists_entity/1` and `add_entity/1`

**program\_database.pl**

```prolog
:- module(
    facts,
    [
      add_entity/1, % +Identifier:string
      exists_entity/1 % ?Identifier:string
    ]
  ).

:- use_module(library(persistency)).

:- persistent
    entity(identifier:string).

:- initialization(db_attach('data.journal', [])).

exists_entity(Identifier):-
  with_mutex(facts_journal, entity(Identifier)).

add_entity(Identifier):-
  with_mutex(facts_journal, assert_entity(Identifier)).

```

* * *

Now to explain it all.

The key to all of this is creating the module **facts** , (`program_database.pl`) which uses `library(persistency)`.

The example you gave was as simple as it can get, it is only one fact `entity/1` with one parameter and no need to use retract.

* * *

The first item needed is access to the `persistency` library

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

```

* * *

The next item that the persistence store needs is a term/spec.

In [library(persistency)](https://www.swi-prolog.org/pldoc/man?section=persistency) it states:

> **persistent** +Spec  
> Declare dynamic database terms. Declarations appear in a directive and have the following format:

```prolog
:- persistent
        <callable>,
        <callable>,
        ...

```

> Each specification is a callable term, following the conventions of library(record), where each argument is of the form

```prolog
  name:type

```

> Types are defined by library(error).

The `type` parameter is found in [must\_be/2](https://www.swi-prolog.org/pldoc/man?predicate=must_be/2) but note that there are more values than listed in the table and list above the table. The real list is in the [code](https://github.com/SWI-Prolog/swipl-devel/blob/a1c4a03e85c71f9724af1f92f54db70460c637fb/library/error.pl#L337) as `has_type/2`

Also note that there can be more than one term/spec associated with a persistence store, but for this example there is only the one, `entity`.

For this example the type `string` will be used.

```prolog
:- persistent
    entity(identifier:string).

```

* * *

The next item that the persistence store needs is some predicates to query/read and assert/write the term/spec.

In [library(persistency)](https://www.swi-prolog.org/pldoc/man?section=persistency) it states:

> The [persistent/1](https://www.swi-prolog.org/pldoc/man?predicate=persistent/1) expands each declaration into four predicates:
> 
> - `name(Arg, ...)`
> - `assert_name(Arg, ...)`
> - `retract_name(Arg, ...)`
> - `retractall_name(Arg, ...)`

These four predicates are created by library(persistence) for each spec, e.g. `entity(identifier:string)` and how user code interacts with the persistence file. However for this case only the first two are needed.

`name(Arg, ...)` - queries/reads the facts from the persistence store/file  
`assert_name(Arg, ...)` - adds facts to the persistence store/file

To ensure no access collisions, [with\_mutex/2](https://www.swi-prolog.org/pldoc/man?predicate=with_mutex/2) is used.

```prolog
exists_entity(Identifier) :-
  with_mutex(facts_journal, entity(Identifier)).

add_entity(Identifier):-
  with_mutex(facts_journal, assert_entity(Identifier)).

```

Now with `exists_entity/1` and `add_entity/1` user code can query/read and assert/write to the persistence store/file/journal.

* * *

The next item that the persistence store needs is a file name.

In [library(persistency)](https://www.swi-prolog.org/pldoc/man?section=persistency) it states:

> **db\_attach** (:File, +Options)
> 
> Use File as persistent database for the calling module. The calling module must defined [persistent/1](https://www.swi-prolog.org/pldoc/man?predicate=persistent/1) to declare the database terms. Defined options:
> 
> **sync** (+Sync)
> 
> One of  
> `close` (close journal after write),  
> `flush` (default, flush journal after write) or  
> `none` (handle as fully buffered stream).
> 
> If _File_ is already attached this operation may change the _sync_ behavior.

```prolog
:- initialization(db_attach('data.journal', [])).

```

* * *

The last item is to convert the code in to a module and export the predicates.

```prolog
:- module(
    facts,
    [
      add_entity/1, % +Identifier:string
      exists_entity/1 % ?Identifier:string
    ]
  ).

```

* * *

The first program creates the data to be persisted makes use of the `facts` module

```prolog
:- use_module('program_database.pl').

```

These predicates work in combination to ensure no value is duplicated in the persistence store, and is stored if it doesn’t exist.

```prolog
    (
        exists_entity(A)
    ;
        add_entity(A)
    )

```

* * *

`halt/0` is run to close the file so that the buffer is flushed. I am sure there is a better way, but I have not needed it so have not looked.

* * *

The second program reads the persisted data makes use of the `facts` module

```prolog
:- use_module('program_database.pl').

```

It only uses a failure driven loop as there can be more than one fact of the same functor.

```prolog
facts:entity(A)

```

If the line is changed to

```prolog
exists_entity(A)

```

it only returns “a” and not “b”. I don’t know why (probably with\_mutex/2). If anyone knows the fix for that I am interested to learn.

* * *

Hopefully this gives you the details you need to expand into what you need. As I noted, there is room for improvement and any feedback is appreciated. 😃

Ask questions if this does not make sense anywhere.

---

<div class="post-metadata">

**Author:** ![aminemarref](https://avatars.discourse-cdn.com/v4/letter/a/7feea3/32.png) [@aminemarref](https://swi-prolog.discourse.group/u/aminemarref)\
**Post date:** [September 25, 2019, 5:40am UTC](https://swi-prolog.discourse.group/t/solving-two-consecutive-dependent-goals-from-command-line/1270/10 "2019-09-25T05:40:08Z")

</div>

Wow, that explanation is great. Intimidation gone! Thank you very much 🙂

I have further questions if you don’t mind.

- Where is the file that holds the asserted facts between the two runs stored?
- Prolog console is gently requesting me to change my queries about the dynamic predicates from `?- entity(A).` to `?- facts:entity(A).`. Does this mean I should replace all my queries about dynamic facts in my program to this style once I have adopted the use of persistence?

Cheers.

---

<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:** [September 25, 2019, 9:50am UTC](https://swi-prolog.discourse.group/t/solving-two-consecutive-dependent-goals-from-command-line/1270/11 "2019-09-25T09:50:18Z")

</div>

> [@aminemarref](#):
>
> Where is the file that holds the asserted facts between the two runs stored?

The path is given by [db\_attach/2](https://www.swi-prolog.org/pldoc/doc_for?object=db_attach/2), e.g.

```prolog
db_attach('data.journal', [])

```

To keep the example simple it used the same directory as the code, e.g.

```prolog
?- working_directory(_, 'C:/Users/Eric/Documents/Projects/Prolog/Persistence example/').
true.

```

Since db\_path/2 can take a full path, you could also do something like

```prolog
db_attach('C:/Users/Eric/Documents/Projects/Prolog/Persistence example/data.journal', [])

```

* * *

@jan Can you check this answer to make sure I am not giving very bad advise.

> [@aminemarref](#):
>
> Prolog console is gently requesting me to change my queries about the dynamic predicates from
> 
> ```prolog
> ?- entity(A).
> 
> ```
> 
> to
> 
> ```prolog
> ?- facts:entity(A).
> 
> ```
> 
> Does this mean I should replace all my queries about dynamic facts in my program to this style once I have adopted the use of persistence?

I would not. That warning is because I still don’t fully know the correct way to use `library(persistency)`.

This also goes back to the statement I made in the explanation.

> [@](#):
>
> If the line is changed to
> 
> ```prolog
> exists_entity(A)
> 
> ```
> 
> it only returns “a” and not “b”. I don’t know why (probably with\_mutex/2).

When writing to a file that can be open by multiple processes at the same time, the use of [with\_mutex/2](https://www.swi-prolog.org/pldoc/man?predicate=with_mutex/2) is probably required. However

```prolog
entity(A).

```

is just trying to read the file and so no lock should be needed and thus `with_mutex/2` should not be needed.

Since the `with_mutex/2` is not needed, the predicate to read the facts, `entity/1` which is in the `facts` module can be exported as is and the wrapper predicate `exists_entity/1` can be removed. The changes to all three source code files becomes

**program\_a.pl**

```prolog
:- use_module('program_database.pl').

program_1 :-
    format('Starting saving ~n',[]),
    A = "a",
    B = "b",
    % Stuff
    %assert(entity(A)),
    (
        % exists_entity(A)
        entity(A)
    ;
        add_entity(A)
    ),
    %assert(entity(B)),
    (
        % exists_entity(B)
        entity(B)
    ;
        add_entity(B)
    ),
    % More stuff
    format('Done ~n',[]).

```

**program\_b.pl**

```prolog
:- use_module('program_database.pl').

program_2 :-
    format('Starting reading program ~n',[]),
    % Stuff
    write_entities.

write_entities :-
    % facts:entity(A),
    % exists_entity(A),
    entity(A),
    write_canonical(A),nl,
    fail.

```

**program\_database.pl**

```prolog
:- module(
    facts,
    [
      add_entity/1, % +Identifier:string
      % exists_entity/1 % ?Identifier:string
      entity/1 % ?Identifier:string
    ]
  ).

:- use_module(library(persistency)).

:- persistent
    entity(identifier:string).

% :- initialization(db_attach('C:/Users/Eric/Documents/Projects/Prolog/Persistence example/data.journal', [])).
:- initialization(db_attach('data.journal', [])).

% exists_entity(Identifier):-
% with_mutex(facts_journal, entity(Identifier)).

add_entity(Identifier):-
  with_mutex(facts_journal, assert_entity(Identifier)).

```

In other words what `library(persistency)` does is, that you give it a `spec` and it creates the 4 predicates

```prolog
name(Arg, ...)
assert_name(Arg, ...)
retract_name(Arg, ...)
retractall_name(Arg, ...)

```

and you give it a file name, e.g. `db_attach('data.journal', [])` and it stores the clauses created by using `assert_name(Arg, ...)` into memory while the programming is running and a file when the program ends. I have not worked with the predicates such as [db\_detach/0](https://www.swi-prolog.org/pldoc/doc_for?object=db_detach/0), [db\_sync/1](https://www.swi-prolog.org/pldoc/doc_for?object=db_sync/1) and [db\_sync\_all/1](https://www.swi-prolog.org/pldoc/doc_for?object=db_sync_all/1) so I can’t say more about them.

The rest is just code I added to make it more useful. It does not even need to be put into a separate module. However in the several cases I used it for and the case you used it for, it makes more sense as a module.

* * *

So you have `library(persistency)` working and know enough to now ask good questions, that pretty much puts you near to what I know about `library(persistency)`, e.g. I only experimented for several hours when I asked the questions in [Trying to understand library(persistency)](https://swi-prolog.discourse.group/t/trying-to-understand-library-persistency/542)

Thanks for asking the questions because it helps to reinforce/change my understanding of using `library(persistency)` and how others are using it and that some of the ways I explain it need more clarification. 😃

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [September 25, 2019, 10:04am UTC](https://swi-prolog.discourse.group/t/solving-two-consecutive-dependent-goals-from-command-line/1270/12 "2019-09-25T10:04:08Z")

</div>

> [@EricGT](#):
>
> @jan Can you check this answer to make sure I am not giving very bad advise.

It looks pretty much ok to me. Personally I dislike absolute paths in code, also because I use quite a few different machines with a different file system layout. I either use simple relative paths or [absolute\_file\_name/3](https://www.swi-prolog.org/pldoc/man?predicate=absolute_file_name/3) and [user:file\_search\_path/2](https://www.swi-prolog.org/pldoc/man?predicate=file_search_path/2) rules to locate (file) resources.
