What is wrong with the following piece of code in prolog? - prolog

I am new to prolog and trying a very simple example on http://www.compileonline.com/execute_prolog_online.php . Here is my code:
:- initialization(main).
main :-
female(ayse).
?- female(ayse).
But it gives an error saying that:
/web/com/136989421322328/main.pr:5:4: syntax error: . or operator expected after expression
1 error(s)
compilation failed
where line 5 is the line starts with ?. What is wrong here? Can anyone help?
Thanks.

This code works:
:- initialization(hello).
hello :- write('hello').
Lines:
you say you want to have a predicate called hello that will be specified in the following lines that shell be executed when everything is loaded.
you declare the predicate.
"hello implies write('hello') is true"
What you wanted to write is
:- initialization(main).
female(ayse).
main :- female(ayse), write('ayse is female').

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.

How to setup a PrologScript

I setup the following rules to find if there is a relationship between two elements:
directReference(A,B) :- projectReferences(A,B).
transitiveReference(A,C) :- directReference(A,B),directReference(B,C).
transitiveReferenceD1(A,D) :- transitiveReference(A,C),directReference(C,D).
transitiveReferenceD2(A,E) :- transitiveReferenceD1(A,D),directReference(D,E).
Can I write a PrologScript that will check all these queries for a fact? Although I plan to use Ruby&Rake, someone is trying to do a non-interactive call from PHP here and it has not worked. I also saw this answer and tried Kaarel's answer. I just added a new opts_spec:
opts_spec(
[ [opt(day), type(atom),
shortflags([d]), longflags(['term', 'day']),
help('name of day')]
, [opt(goal),
shortflags([g]), longflags([goal]),
help('goal to be called')]
, [opt(projectReferences), type(atom),
shortflags([pr]), longflags(['term', 'projectReferences']),
help('Project Reference lookup')]
]
).
I then compiled with:
.\swipl.exe -o day.exe -g main -c "D:\DevProjects\AskJoe\Output\Sample.pro"
And ran it with:
./day.exe -g "day(Sunday)"
And got error:
ERROR: Prolog initialisation failed: ERROR: validate_opts_spec/1:
Domain error: unique_atom' expected, foundterm' (ambiguous flag)
My goal is to have this work:
./day.exe -g "transitiveReference('a','b')"
I don't like compiling a "day.exe" to run a script (according to the docs this often is not necessary), but I have found no other way to pass arguments to rules.
I saw a basic intro on swi-pl.org that has not helped much. It does not explain how to make the leap from the script.sh file example to the execution of ./eval 1+2. In fact, the example is a comment so I'm totally lost
Here is a very crude example of a PrologScript program that will read its arguments as a single goal (which may be compound), call it, and then terminate. It should work on *nix systems, and has been tested on OS X. It is just a slight variation of the example program given for using PrologScript in the SWI docs:
#!/usr/bin/env swipl
:- initialization main.
query :-
current_prolog_flag(argv, Argv),
concat_atom(Argv, ' ', Atom),
read_term_from_atom(Atom, Term, []),
call(Term).
main :-
catch(query, E, (print_message(error, E), fail)),
halt.
main :-
halt(1).
projectReferences(valueA, valueB) :- writeln('I was called!').
directReference(A,B) :- projectReferences(A,B).
transitiveReference(A,C) :- directReference(A,B),directReference(B,C).
transitiveReferenceD1(A,D) :- transitiveReference(A,C),directReference(C,D).
transitiveReferenceD2(A,E) :- transitiveReferenceD1(A,D),directReference(D,E).
After saving this file as, e.g., cli_test.pl, you'll need to change the permissions on the file so that the operating system will recognize it as an executable:
chmod -x scratchboard.pl
After that, you should be able to call the file as as a normal executable from the command line:
$ path/to/the/file/scratchboard.pl 'transitiveReferenceD1(A,D).'
I was called!
Note:
The goal to be evaluated is simply passed as a single argument. query/0 will then retrieve this argument using current_prolog_flag/2, read it as a Prolog term, and call it.
Since the program is not running in interactive mode, the only output will result from explicit imperatives to write out, such as occur if catch/3 (in the body of main/0) is triggered by an error or if projectReferences/2 is called successfully.
Using library(optparse) seems advisable for more complicated cli interface, but is not necessary for your stated aim of merely querying goals in a file.
I understand that getting the PrologScript approach to work on Windows is somewhat different. A bit of information can be fond here: http://www.swi-prolog.org/FAQ/PrologScript.html
So I got this all working and then after a few runs everything just stopped. I started getting 'permission denied bad interpreter' errors. All I can say is that it has something to do with the hashBang. The workaround for me was to create a shell script around the call to swipl:
shellscript.sh
#!/bin/bash
swipl -s script4.pl 'projectReferences(A,D).'
Then I continued using aBathologist's example, but just took off the hashBang:
:- initialization main.
query :-
current_prolog_flag(argv, Argv),
concat_atom(Argv, ' ', Atom),
read_term_from_atom(Atom, Term, []),
call(Term).
main :-
catch(query, E, (print_message(error, E), fail)),
halt.
main :-
halt(1).
projectReferences(valueA, valueB) :- writeln('I was called!').
directReference(A,B) :- projectReferences(A,B).
transitiveReference(A,C) :- directReference(A,B),directReference(B,C).
transitiveReferenceD1(A,D) :- transitiveReference(A,C),directReference(C,D).
transitiveReferenceD2(A,E) :- transitiveReferenceD1(A,D),directReference(D,E).

Read a file line by line error in prolog

For reading a file i'm using below code, but this code reads only lines where there is a '.' in the end of file, is there another way to read any kind of file and store in the list?
main :-
open('myFile.txt', read, Str),
read_file(Str,Lines),
close(Str),
write(Lines), nl.
read_file(Stream,[]) :-
at_end_of_stream(Stream).
read_file(Stream,[X|L]) :-
\+ at_end_of_stream(Stream),
read(Stream,X),
read_file(Stream,L).
I took this code from this link
Read a file line by line in Prolog
Please note that the code you wrote is inherently incorrect for the following reasons.
1mo, you are reading Prolog data, and not lines at all. Take a. b. c. which would make a list [a,b,c].
2do, testing for at_end_of_stream/1 is extremely tricky, and does not work as expected when reading Prolog data. Take the 3-line file:
first_fact.
second_fact.
% no comment - oh that's a comment nevertheless
This will give you the list [first_fact, second_fact, end_of_file]. For read/1 gives you a term end_of_file after having read the last line.
3tio, upon backtracking, main will always produce an error!
?- main.
[first_fact,second_fact,end_of_file]
true ;
ERROR: at_end_of_stream/1: stream `<stream>(0x1c38330)' does not exist
If you want to read just bytes use library(pio). And to use that, first learn the dcg formalism.
The following will succeed for each occurrence of magic in the file:
?- phrase_from_file((..., "magic", ...), filename).
using the following definition of ... //0:
... --> [] | [_], ... .
See this for more.

running prolog as a script

So, I have some Prolog code that models variable assignments, such as in a programming language, and tries to see if they are compatible with one another. So,
assigned(X, X).
and(P, Q) :- P, Q.
or(P, Q) :- P.
or(P, Q) :- Q.
% and then we should test an expression like this:
and(assigned(X, 5), assigned(X, 6)).
So that last expression fails, since X can't be assigned to both 5 and 6.
Now, what I want to do is have this test a single expression (which can and should be hardcoded into the file), and then simply print out whether or not it's able to be satisfied. But it seems that SWIPL really wants me to run interactively. Ideally, something like this:
> ./test-assignments
false.
Surely this is possible? I'm at my wit's end on this.
There are several ways to get an SWI-Prolog program to run directly from the shell. You can look at this question and the answers:
How to run SWI-Prolog from the command line?
My personal preference now is to have a file example.pl like this:
:- set_prolog_flag(verbose, silent).
:- initialization(main).
main :-
format('Example script~n'),
current_prolog_flag(argv, Argv),
format('Called with ~q~n', [Argv]),
halt.
main :-
halt(1).
which I then run from the command line with:
$ swipl example.pl and a few arguments
Example script
Called with [and,a,few,arguments]
The initialization directive tells the interpreter which goal to evaluate after it loads the program: here it is main/0. The name main is a convention, it could have been called anything else.
See the linked question and answers for other options.

First use of SWI-Prolog

I'm brand new to Prolog. I am simply trying to get some output from Prolog on Windows Vista.
I have downloaded and installed Prolog 5.1; I chose the .pro file extension when installing (not to confuse with Perl files).
I created a file called test.pro.
Inside this file I put the following:
inside(tom).
?-inside(tom).
I double clicked the file and a command line interface popped up. On this interface (after a bunch of generic Prolog version/copyright info) the only output is:
1 ?-
OK, for starters, I did not expect it to ask a question; I expected it to answer a question (something along the line of 'yes').
Anyway, I tried to respond to the query with the following:
In the command line I re-inserted 'inside(tom).', so the whole line looks like:
1 ?- inside(tom).
I pressed Enter and got an error message:
ERROR: toplevel: Undefined procedure: inside/1 (DWIM could not correct goal)
Prolog doesn't answer questions if you haven't told it facts. (Except for some built-in facts such as member(1, [1,2,3]).)
You can tell it who is inside by (comment follow a %):
1 ?- [user]. % get facts and rules from user input
|: inside(mary). % Mary and John are explicitly inside
|: inside(john).
|: inside(X) :- location(X, house). % rule: anyone in the house is inside
|: inside(X) :- location(X, office). % (variables start with a capital letter)
|:
|: location(tom, house).
|: location(bernard, house).
|: location(anne, office).
|: % type Ctrl+D
% user://1 compiled 0.00 sec, 1,220 bytes
true.
2 ?- inside(tom). % Prolog deduces that Tom is inside
true .
If you want to learn Prolog, Learn Prolog Now is a good, free tutorial.
You need to compile this first (also called "consult" in prolog). If I knew which version of prolog you have I could find out the exact key entry for this command (Ctrl-L may work). By the way, welcome to the wonderful world of prolog- I love it :) As soon as you're over this hurdle, it gets a lot better. :)
Quick and dirty. What was missing was 'compiling' the file, known as consult
and the syntax is as follows, all characters in the line are relevant.
?- [filename].
then you can ask questions and do other things with what the database.(the source code in prolog)
http://www.swi-prolog.org/pldoc/man?section=quickstart

Resources