Open .pl file and close current one in SWI - Prolog - prolog

I have created two different .pl files in SWI-Prolog for a text adventure game. They are two different missions.
Is there any way at the end of the first mission to open the second mission (the second .pl file) and close the first one?
Also, what would be better: To create N .pl files for my N missions or one big .pl file?

I agree with your initial impulse in thinking that using a number of module files would be best. I imagine that one reason for using different files would be to provide different name spaces for facts and rules which would be best expressed using the same predicates. So that, for instance, Description would be different for room(1, Description) in mission 1 than in mission 2.
One way of achieving this would be by accessing private, non-exported predicates in each of the different mission-modules. (Aside: I read Jan Wielemaker caution against this practice somewhere, but I'm not sure why, nor am I sure that I did read this.)
Here's a possible pattern I threw together:
Given a main file, 'game.pl', with the following program,
:- use_module([mission1, mission2]).
start :-
playing(mission1).
playing(CurrentMission) :-
read(Command),
command(CurrentMission, Command),
playing(CurrentMission).
command(_, quit) :- write('Good bye.'), halt.
command(CurrentMission, Command) :-
( current_predicate(CurrentMission:Command/_) % Makes sure Command is defined in the module.
-> CurrentMission:Command % Call Command in the current mission-module
; write('You can\'t do that.'), % In case Command isn't defined in the mission.
).
and these mission modules,
In file 'mission1.pl':
:- module(mission1, []).
turn_left :-
write('You see a left-over turnip').
eat_turnip :-
write('You are transported to mission2'),
playing(mission2). % Return to the prompt in `game` module, but with the next module.
In file 'mission2.pl':
:- module(mission2, []).
turn_left :-
write('You see a left-leaning turncoat.').
Then we can play this shitty game:
?- start.
|: turn_left.
You see a left-over turnip
|: eat_turnip.
You are transported to mission2
|: turn_left.
You see a left-leaning turncoat.
|: quit
|: .
Good bye.
The specifics of this program are problematic for a number of reasons. For instance, I expect we might rather have a single predicate that handles navigating through places, and that we'd rather describe places and object that react to different commands in our missions, rather than account for every possible command. But the general principle of using the different files would still work.
Another approach would be to use consult/1 and unload_file/1 to load and unload modules, in which case you should be able to use their public, exported predicates instead of calling them by module. Documentation for those and related predicates can be found in the manual in the section "Loading Prolog Source Files".

Related

How to display all the results in one line in SWI PROLOG?

I have a small databse in the *.pl file which contains various instances of 3 facts:
male(NAME)
female(NAME)
parents(CHILD_NAME, MOTHER_NAME, FATHER_NAME)
and one question:
brother(A, B) :- male(A), parents(A ,X, Y), parents(B, X, Y), X\==Y.
which tells when X is a brohter of Y. The question is: is here any way to display all the answers in one line while running the question without hitting ';' for every new instance?
I think I would write once an utility like
writeall(Q) :- forall(Q,writeln(Q)).
In SWI-prolog there is an handy place where to store utility snippets like this one. From the IDE, click the menu
Edit\Prolog preferences
and save the snippet there. It get stored in ~/.swiplrc on Linux, MacOS, or into an equivalent configuration file under Windows.

Prolog Returning Elements Within Facts to The User

I have a Prolog knowledge base with some "symptom" facts called facts.pl. Here is an example of my KB:
symptom("Typhoid", "muscle_pain").
symptom("Typhoid", "bloating").
symptom("Meningitis", "headache").
symptom("Meningitis", "fever").
symptom("Meningitis", "stiff neck" ).
symptom("Measles", "cough").
symptom("Measles", "runny_nose").
I have written a short prolog program in another file called "diseaseSearch.pl". This program consults facts.pl and is supposed to allow the user to enter a disease name and prints the disease's corresponding symptoms to the screen.
My code:
:- write('loading disease database'), nl.
:- [facts].
:- write('disease database loaded'), nl, nl.
getsymptoms:-
write('> Enter a diseae name followed by a period.'), nl,
write('For Example: Measles'), nl,
write('Disease Name?:'),
read(Input), nl,
symptom(Input,Output),
write(Output).
If I enter "Measles." the output should be "cough" and "runny_nose". However, with the code above no matter which disease I enter it always returns the result from the first fact which is "muscle_pain". SWI output found here
I found a similar method from an online tutorial, I am trying to learn the basics of Prolog input and output right now. Am I on the right track? Some tips to solve this problem would be greatly appreciated!
I guess you are entering Measles without " " and prolog takes it as a variables. Either you should enter it with "". If you enter Measles then it's a variables but if you enter "Measles" then it's a term.
If you want to enter without annotations then you need to make a database in which you have all terms(means that they start with small letter) then you don't need annotation.

Arguments not sufficiently instantiated when consulting file

I'm running SWI-Prolog on a Mac through the Terminal. I'm trying to access an Atom file by writing the usual after opening up swipl in the terminal:
?- [hwk1-my_name].
Instead of swipl having the knowledge base to play with, it's giving me this:
ERROR: Arguments are not sufficiently instantiated
I'm new to Prolog, and my program as it stands now is simply the copied-and-pasted code provided by my professor to get the assignment started. Does this mean that the error is likely due to something within the code below, and if so, what is prompting this? Here is the code provided to me:
father(Dad, Child) :-
parent(Dad, Child),
male(Dad).
mother(Mom, Child) :-
parent(Mom, Child),
female(Mom).
had_a_child(Man, Woman) :-
father(Man, Child),
mother(Woman, Child).
sibling(Sibling1, Sibling2) :-
parent(Parent, Sibling1),
parent(Parent, Sibling2),
Sibling1 \= Sibling2.
brother(Brother, Sib) :-
sibling(Brother, Sib),
male(Brother).
sister(Sister, Sib) :-
sibling(Sister, Sib),
female(Sister).
Your obvious problem is the - inside the file name. The text editor you are using is completely irrelevant. Even confusing, as one of Prolog's data types is the atom.
You have two options:
Use file names that would be valid Prolog atoms even without quoting. This means that they cannot start with a capital or a digit, and can contain only letters, digits, and underscores (_). Then, your file can still have the .pl extension and you can consult it like you do: foo.pl ---> ?- [foo].
Use the complete filename, extension included, and put single quotes around it: foo-bar.baz ---> ?- ['foo-bar.baz'].. As you will see, you don't even need the .pl extension any more.
Whenever you are in doubt about what Prolog sees, you can try write_canonical/1:
?- write_canonical(hwk1-my_name).
-(hwk1, my_name)
true.
In other words, Prolog takes this as the compound term -/2 with the atoms hwk1 and my_name as the first and second argument.

Defining predicates in SICStus Prolog / SWI-Prolog REPL

I am reading http://cs.union.edu/~striegnk/learn-prolog-now/html/node3.html#subsec.l1.kb1,
but I am having trouble running the following predicate:
SICStus 4.0.1 (x86-win32-nt-4): Tue May 15 21:17:49 WEST 2007
| ?- woman(mia).
! Existence error in user:woman/1
! procedure user:woman/1 does not exist
! goal: user:woman(mia)
| ?-
If, on the other hand, I write it to a file and run consult the file, it seems to work fine...
Am I only allowed to define predicates in a file having later to consult them? Can't I just do it in the editor itself?
It's a little annoying to make predicates in the repl. You could do
| ?- ['user'].
woman(mia).
^D
ie consult user input, or
| ?- assertz(woman(mia)).
assert it. Both awkward IMO -- there might be a better way, though, I just don't know it. In general it is easier to use a script.
You should enter woman(mia). into a file to assert it as a fact. If you write it into the interpreter, it's taken as a query, not a fact.
From the SWI Prolog FAQ:
Terms that you enter at the toplevel are processes as queries, while
terms that appear in a file that is loaded into Prolog is processed as
a set of rules and facts. If a text reads as below, this is a rule.
carnivore(X) :- animal(X), eats_meat(X).
Trying to enter this at the toplevel results in the error below. Why?
Because a rule is a term :-(Head, Body), and because the toplevel
interprets terms as queries. There is no predicate with the name :-
and two arguments.
?- carnivore(X) :- animal(X), eats_meat(X). ERROR: Undefined
procedure: (:-)/2 ERROR: Rules must be loaded from a file ERROR:
See FAQ at http://www.swi-prolog.org/FAQ/ToplevelMode.txt
Isn't this stupid? Well, no. Suppose we have a term
eats_meat(rataplan). If this appears in a file, it states the fact
that rataplan eats meat. If it appears at the toplevel, it asks Prolog
to try proving whether rataplan eats meat.
If a text reads
:- use_module(library(clpfd)).
This is a directive. Directives are similar to queries, but instead of
asking the toplevel to do something, they ask the compiler to do
something. Like rules and facts, such terms belong in files.
Instead of writing to a file you can also use assert in the toplevel (as explained later in the FAQ as well).

Defining a rule that the user cannot query

How do I define a rule that the user cannot query?
I only want the program itself to call this rule through another rule.
Ex:
rule1():- rule2().
rule2():- 1<5.
?-rule1().
true
?-rule2().
(I don't know what the answer will be, I just want this query to fail!)
Use a Logtalk object to encapsulate your predicates. Only the predicates that you declare public can be called (from outside the object). Prolog modules don't prevent calling any predicate as using explcit qualification bypasses the list of explicitly exported predicates.
A simple example:
:- object(rules).
:- public(rule1/1).
rule1(X) :-
rule2(X).
rule2(X) :-
X < 5.
:- end_object.
After compiling and loading the object above:
?- rules::rule1(3).
true.
?- rules::rule2(3).
error(existence_error(predicate_declaration,rule2(3)),rules::rule2(3),user)
If you edit the object code and explicitly declare rule2/1 as private you would get instead the error:
?- rules::rule2(3).
error(permission_error(access,private_predicate,rule2(3)),rules::rule2(3),user)
More information and plenty of examples at http://logtalk.org/
First, some notes:
I think you mean "predicate" instead of "rule". A predicate is a name/k thing such as help/0 (and help/1 is another) and can have multiple clauses, among them facts and rules, e.g. length([], 0). (a fact) and length([H|T], L) :- ... . (a rule) are two clauses of one predicate length/2.
Do not use empty parenthesis for predicates with no arguments – in SWI-Prolog at least, this will not work at all. Just use predicate2 instead of predicate2() in all places.
If you try to call an undefined predicate, SWI-Prolog will say ERROR: toplevel: Undefined procedure: predicate2/0 (DWIM could not correct goal) and Sicstus-Prolog will say {EXISTENCE ERROR: predicate2: procedure user:predicate2/0 does not exist}
Now, to the answer. Two ideas come to my mind.
(1) This is a hack, but you could assert the predicate(s) every time you need them and retract them immediately afterwards:
predicate1 :-
assert(predicate2), predicate2, retractall(predicate2).
If you want a body and arguments for predicate2, do assert(predicate2(argument1, argument2) :- (clause1, clause2, clause3)).
(2) Another way to achieve this would be to introduce an extra argument for the predicate which you do not want to be called by the user and use it for an identification that the user cannot possibly provide, but which you can provide from your calling predicate. This might be a large constant number which looks random, or even a sentence. This even enables you to output a custom error message in case the wrong identification was provided.
Example:
predicate1 :-
predicate2("Identification: 2349860293587").
predicate2(Identification) :-
Identification = "Identification: 2349860293587",
1 < 5.
predicate2(Identification) :- Identification \= "Identification: 2349860293587",
write("Error: this procedure cannot be called by the user. Use predicate1/0 instead."),
fail.
I don't use the equivalent predicate2("Identification: 2349860293587") for the first clause of predicate2/0, because I'm not sure where the head of the clause might appear in Prolog messages and you don't want that. I use a fail in the end of the second clause just so that Prolog prints false instead of true after the error message. And finally, I have no idea how to prevent the user from looking up the source code with listing(predicate2) so that will still make it possible to simply look up the correct identification code if s/he really wants to. If it's just to keep the user from doing accidental harm, it should however suffice as a protection.
This reminds me to facility found in Java. There one can query the
curent call stack, and use this to regulate permissions of calling
a method. Translated to Prolog we find in the old DEC-10 Prolog the
following predicate:
ancestors(L)
Unifies L with a list of ancestor goals for the current clause.
The list starts with the parent goal and ends with the most recent
ancestor coming from a call in a compiled clause. The list is printed
using print and each entry is preceded by the invocation number in
parentheses followed by the depth number (as would be given in a
trace message). If the invocation does not have a number (this will
occur if Debug Mode was not switched on until further into the execution)
then this is marked by "-". Not available for compiled code.
Since the top level is usually a compiled predicate prolog/0, this could be
used to write a predicate that inspects its own call stack, and then decides
whether it wants to go into service or not.
rule2 :- ancestors(L), length(L,N), N<2, !, write('Don't call me'), fail.
rule2 :- 1<5.
In modern Prologs we don't find so often the ancestors/1 predicate anymore.
But it can be simulated along the following lines. Just throw an error, and
in case that the error is adorned with a stack trace, you get all you need:
ancestors(L) :- catch(sys_throw_error(ignore),error(ignore,L),true).
But beware stack eliminiation optimization might reduce the stack and thus
the list returned by ancestors/1.
Best Regards
P.S.: Stack elimination optimization is already explained here:
[4] Warren, D.H.D. (1983): An Abstract Prolog Instruction Set, Technical Note 309, SRI International, October, 1983
A discussion for Jekejeke Prolog is found here:
http://www.jekejeke.ch/idatab/doclet/prod/en/docs/10_pro08/13_press/03_bench/05_optimizations/03_stack.html

Resources