Separating Knowledge Base from Predicates, get "undefined procedure" - prolog

Why isn't father/2 recognized and why can't I load a file that calls father/2?
theogony.pl
father(kronos, zeus).
father(zeus, ares).
mythos.pl
consult('theogony.pl').
%% --
%% X is an ancestor of Y
%% --
ancestor(X,Y) :-
father(X,Y).
ancestor(X,Y) :-
ancestor(X,Z),
ancestor(Z,Y).
swipl
?- consult('mythos.pl').
false.
?- consult('theogony.pl').
true.
?- father(X,zeus).
ERROR: Unknown procedure: father/2 (DWIM could not correct goal)

As noted there are two Prolog files with the file type pl. This code works with both files in the same directory, e.g. 'C:/Users/Groot/Example_01'. You can use another directory but be consistent with the directory name.
Directory: 'C:/Users/Groot/Example_01'
File: 'theogony.pl'
:- module(theogony,
[
father/2
]).
father(kronos, zeus).
father(zeus, ares).
Directory: 'C:/Users/Groot/Example_01'
File: 'mythos.pl'
:- module(mythos,
[
ancestor/2
]).
ancestor(X,Y) :-
father(X,Y).
ancestor(X,Y) :-
ancestor(X,Z),
ancestor(Z,Y).
Start SWI-Prolog
Welcome to SWI-Prolog (threaded, 64 bits, version 8.5.15)
...
?-
I know, there is a newer version but this is so basic even the really old versions should work.
Change the working directory.
?- working_directory(_,'C:/Users/Groot/Example_01').
true.
Use consult which is also done using [] to load the Prolog files.
?- [theogony].
true.
?- [mythos].
true.
Run your query.
?- father(X,zeus).
X = kronos.

Related

How to use assert and retract in SWI-Prolog

In SWI-Prolog, if I use assert and retract at the prompt, I get
?- assert(at(1)).
true.
?- retract(at(1)).
true.
However, if I put these statements into a program file called "test" as
assert(at(1)).
retract(at(1)).
and run SWI-Prolog as
> swipl
?- [test].
I get
ERROR: /....../test:2:
No permission to modify static procedure `retract/1'
true.
What does this mean and how should I deal with it?
Put statements within a predicate, e.g.:
:- dynamic at/1.
test_assert :-
assert(at(1)).
test_retract :-
retract(at(1)).
Load the program, and then run:
?- test_assert.
true.
?- at(X).
X = 1.
?- test_retract.
true.
?- at(X).
false.
The prompt and source code files are different environments with slightly different behaviours. It's like the difference between calling Python len(x) in the repl and writing function len(x): in Python source code - you would be overriding the builtin len() with your own one. Python lets you do that, SWI Prolog also does but not easily.
When you type them at the prompt, you call the existing predicate assert/1 and actually do insert the fact at(1). into the database. When you type retract/1 you actually do retract the fact at(1) from the database.
In a fresh prompt, try ?- listing(at). and get an error, then ?- assert(at(1)). then do the listing again and see the fact, then retract it and try the listing and see only the remains of the dynamic declaration and the fact is gone.
When you put them in a source code file, you would be trying to override the existing builtin predicates with your new ones. Your new ones say "assert/1 is a predicate which succeeds when its arugment unifies with at(1)" and "retract/1 is a predicate which succeeds when its arugment unifies with at(1)".
That is, they don't do any asserting or retracting or database changes.
In your test file, put this:
:- redefine_system_predicate(assert(_)).
:- redefine_system_predicate(retract(_)).
assert(at(1)) :- true.
retract(at(1)) :- true.
Then save and consult it:
?- [testing].
true.
?- listing(at). % <-- your code ran, but did not insert `at(1)`.
ERROR: procedure `at' does not exist (DWIM could not correct goal)
^ Exception: (13) setup_call_catcher_cleanup(system:true, prolog_listing:listing_(user:at, []), _19450, prolog_listing:close_sources) ? abort
% Execution Aborted
?- assert(P). % <-- it's now behaving
P = at(1). % <-- like any other predicate.

Outputting prolog in Mac

I have a problem using prolog on a Mac, I figured out how to run it using SWI-Prolog but when I run it, it gives an error and does not give the expected output
Expected output: homer, bart
male(homer).
male(bart).
female(marge).
female(lisa).
female(maggie).
parent(homer, bart).
parent(homer, lisa).
parent(homer, maggie).
parent(marge, bart).
parent(marge, lisa).
parent(marge, maggie).
mother(X, Y) :- parent(X, Y), female(X).
father(X, Y) :- parent(X, Y), male(X).
son(X, Y) :- parent(Y, X), male(X).
daughter(X, Y) :- parent(Y, X), female(X).
?- male(X).
Here is the error I was speaking about earlier
Warning: /Users/[username]/Desktop/simpsons.pl:19:
Warning: Singleton variables: [X]
true.
And instead of outputting homer, bart it outputs true
When programming in Prolog, you put definitions and queries in different places. Definitions go into source files. Queries do not go into source files. You enter them while interacting with the Prolog system in something called the "toplevel" or "prompt" or "shell" or maybe "REPL" (read-eval-print loop).
For example, these are definitions:
male(homer).
male(bart).
female(marge).
female(lisa).
female(maggie).
You have put them in a source file called simpsons.pl. This is correct.
This is not a definition but a query:
?- male(X).
This does not go in a source file. Do not put it in simpsons.pl. Rather, you:
start your Prolog system
load the simpsons.pl file somehow
enter the query male(X). and observe answers
This video: https://www.youtube.com/watch?v=t6L7O7KiE-Q shows these steps with SWI-Prolog on a Mac.
If you are comfortable using a command line, you might also be able to do this simpler. For example, on my (Linux) machine, I can start SWI-Prolog with a command line argument naming a file to be loaded:
$ swipl simpsons.pl
Welcome to SWI-Prolog (threaded, 64 bits, version 7.6.4)
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).
?-
See that ?-? That is the prompt meaning that the toplevel is now waiting for your input. Here is where you enter your male(X) query. You can use ; or Space to cycle through the various answers:
?- male(X).
X = homer ;
X = bart.

Redirect SWI-Prolog console output to a file

I'm trying to write output from make_tests to a file, but nothing I've tried seems to insert the correct information in the output file.
I've looked at SWI documentaion at http://www.complang.tuwien.ac.at/SWI-Prolog/Manual/IO.html and have tried a whole bunch of those predicates but none have worked.
Here's what I'm trying to do:
:- use_module(library(test_wizard)).
init_test_file(FILE) :-
set_prolog_flag(log_query_file, FILE).
gen_test_in(FILE) :-
make_tests(lists, FILE, current_output).
So running this (in console) for example:
init_test_file('mytest.pro').
member(a, [a,b]).
gen_test_in('mytest.pro').
I get the following output (in console):
true.
6 ?- gen_test_in('r.pro').
:- begin_tests(lists).
test(member, [nondet]) :-
member(a, [a, b]).
:- end_tests(lists).
true.
How do I get this same output (starting at begin_tests and ending at end_tests in a text file?
I tried doing things like modifying gen_test_in to:
gen_test_in(FILE) :-
open(FILE, write, Out),
make_tests(lists, FILE, Out),
close(Out).
But I just get an empty text file.
You are messing up the arguments here. The library you are using, library(test_wizard), is meant for generating tests from queries. In the predicate you are using, make_tests/3, you have the following three arguments:
The module
The file from which the queries are read
The stream to which the generated tests are written
In the examples you use, you either set your output stream to be current_output (so standard output if you are on the top level), or, in the last example you give, you are opening the file you want to read for writing, and then pass the file and its handle to make_tests/3. Instead, if you have a file called queries.pl:
$ cat queries.pl
member(a, [a,b]).
member(X, [a,b]).
Then:
$ swipl
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.16-36-g42820df)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.
For help, use ?- help(Topic). or ?- apropos(Word).
?- use_module(library(test_wizard)).
true.
?- setup_call_cleanup(open('lists.plt', write, Out),
make_tests(lists, 'queries.pl', Out),
close(Out)).
Out = <stream>(0xe59ef0).
?- halt.
$ cat lists.plt
:- begin_tests(lists).
test(member, [nondet]) :-
member(a, [a, b]).
test(member, [all(A==[a, b])]) :-
member(A, [a, b]).
:- end_tests(lists).

SWI-Prolog doesn't show result

I'm Prolog beginner, and now I'm stuck, because Prolog doesn't show me any result. I'm reading a few tutorials, and all they has an example code like this:
main.
human(ann).
human(george).
human(mike).
?- bagof(H, human(H), Humans).
% Expected result:
% Humans = [ann, george, mike].
?- human(Who).
% Expected result:
%
% Who = ann;
% Who = george;
% Who = mike.
But all output I get is:
Warning: /Users/admin/prolog/test.pl:105:
Singleton variables: [Who]
% test.pl compiled 0.00 sec, 34 clauses
true.
Or:
Warning: /Users/admin/prolog/test.pl:105:
Singleton variables: [Humans]
% test.pl compiled 0.02 sec, 1,409 clauses
true.
What am I doing wrong? I really read everything I could, but all manuals say that such code must return result. But it doesn't for me.
SWI-Prolog version: 6.6.5 for x86_64-darwin13.1.0
OS: MAC OS X 10.9.2 Maverix
If you go back to the tutorials you've been looking at, they should be making clear (as #PauloMoura points out) that there's a difference between consulting a file in Prolog and interacting with Prolog at it's interactive prompt.
If you simply run Prolog without consulting a file, you can manually enter facts and rules, then press ctrl-D to finish. For example:
? - [user].
|: human(ann).
|: human(george).
|: human(mike).
|: % user://1 compiled 0.00 sec, 2 clauses
true.
Then you can query by typing (at the shown prompt):
?- human(Who).
Who = ann ;
Who = george ;
Who = mike.
?- bagof(H, human(H), Humans).
Humans = [ann, george, mike].
?-
If you want to put things in a file, you can put your facts in a file, say, humans.pl:
human(ann).
human(george).
human(mike).
Then consult the file from the Prolog prompt:
?- [humans].
% humans compiled 0.00 sec, 5 clauses
true.
And then do my queries (again, manually in this case) shown above with the same results:
?- human(Who).
Who = ann ;
Who = george ;
Who = mike.
?- bagof(H, human(H), Humans).
Humans = [ann, george, mike].
These outputs are provided courtesy of the interactive prompt. If you want to have everything in the file, you need to have a predicate in the file which would use I/O functions to output the information you want.
So we can make humans.pl look like this:
human(ann).
human(george).
human(mike).
?- human(Who), write(Who), nl, fail.
?- bagof(H, human(H), Humans), write(Humans), nl.
And then you'd get:
?- [humans].
ann
george
mike
Warning: /home/mark/src/prolog/_play_/humans.pl:5:
Goal (directive) failed: user: (human(_G606),write(_G606),nl,fail)
[ann,george,mike]
% humans compiled 0.00 sec, 5 clauses
true.
?-
The warning comes because the first query fails (used to do the backtrack for more results). you can get rid of that failure just by adding an alternative true path to that query:
?- human(H), write(H), nl, fail ; true.
Or, you can introduce a single predicate to output all the humans:
human(ann).
human(george).
human(mike).
show_humans :-
human(H),
write(H), nl,
fail.
show_humans.
?- show_humans.
?- bagof(H, human(H), Humans), write(Humans), nl.
Which results in:
?- [humans].
ann
george
mike
[ann,george,mike]
% humans compiled 0.00 sec, 7 clauses
true.
It seems that you're writing your queries in the file itself instead of trying them at the Prolog top-level interpreter. Queries in a file such as ?- human(Who). are (usually) executed silently. The queries in your file are also the reason you're getting the singleton variable warnings. If you want a query embed in a source file to output anything you need to explicitly add the necessary calls to output the results.
If you want to use Prolog in batch mode, not in interactive mode, you can write the code in human.pl.
:- initialization main.
human(ann).
human(george).
human(mike).
main :-
bagof(X, human(X), L),
write(L),
halt.
To run it with swipl human.pl (I use swi prolog). Then, the results will be:
% human.pl compiled 0.00 sec, 6 clauses
[ann,george,mike]

SWI-Prolog - Fail to Assert

I define an operator as follows:
:- op(500, xfx, =>).
When I try something like:
assert(a => b).
Prolog raises an error that says 'No permission to modify static_procedure (=>)/2'.
Any solution?
As a security, you have to warn SWI that you are going to modify a predicate at runtime:
:- dynamic (=>)/2.
put at the top of the file should do it.
You must have meant another symbol in place of (=>)/2. Probably (->)/2 which is a control construct that cannot be modified.
Welcome to SWI-Prolog (Multi-threaded, 32 bits, Version 6.1.3-116-gf1c7e06)
...
?- asserta((a -> b)).
ERROR: asserta/1: No permission to modify static procedure `(->)/2'
ERROR: Defined at /opt/gupu/pl-devel/lib/swipl-6.1.3/boot/init.pl:194
?- op(500, xfx, =>).
true.
?- asserta(a => b).
true.

Resources