i'm a total newbie in Prolog and learning it while taking a course in school. We have this big test coming up tomorrow and as i'm studying here i tried to do some tasks from previous versions of this test. One particular task was to take a string and put a "-" after every character "a". So for example word "example" would look like "exa-mple".
I wrote a code for it:
kriipsuga(S6ne,R) :-
name(S6ne,X),
write(X),
goThrough(X,Y),
name(R,Y).
goThrough([X|Xs],Y) :-
X == 97,
append(Y,[97],Z),
append(Z,[45],O),
goThrough(Xs,O).
goThrough([X|Xs],Y) :-
X \= 97,
append(Y,[X],O),
goThrough(Xs,O).
goThrough([],Y) :- write(Y),Y.
This is the error:
?- goThrough([1,2,3,4],Y).
[1, 2, 3, 4]
ERROR: Unhandled exception: is_absolute_file_name/1: Type error: `text' expected, found `1'
Googling gave no results, maybe you guys could help me figure it out.
Thanks :)
The shortcut [File1, File2, ...] is traditionally used in Prolog as a shorthand to the predicate that compiles and load a source files (usually, consult/1). The file argument is expanded into an absolute file path. In you code, the last clause is:
goThrough([],Y) :- write(Y),Y.
In your sample query, this clause ends up being used and a call [1|_] is made, hence the error you get. To make it clear, try to trace execution using the query:
?- trace, goThrough([1,2,3,4],Y).
Related
I'm studying for an exam and got stuck on one of the prep questions:
Question:
The following Prolog-program is a meta-program. Explain why this
program is a meta-program and give the output to the three questions
to the program:
?- prove(moving_method(bird,M),N).
?- prove(moving_method(ross,M),N).
?- prove(moving_method(kim,M),N).
I'm trying to run the code(on swish.swi-prolog.org) but it only gives me this error message:
Sandbox restriction!
Could not derive which predicate may be called from
call(C)
prove(A,B)
prove(moving_method(bird,A),B)
The code we are given:
:- dynamic moving_method/2, is_a/2.
is_a(bird,animal).
is_a(ross,albatross).
is_a(kim,kiwi).
is_a(albatross,bird).
moving_method(bird,fly).
moving_method(kiwi,walk).
prove(Fact,l):-
Fact,!.
prove(Fact,X):-
Fact=..[Rel,A1,A2],
is_a(A1,SA),
NewFact=..[Rel,SA,A2],
prove(NewFact,X1),
X is X1 + 1.
The error message might be fairly straight forward but how do I fix it? And why is this a meta-program?
Thank you!
why is this a meta-program?
See: SWI-Prolog Meta-Call Predicates
Meta-call predicates are used to call terms constructed at run time.
In this case passing in the predicate to call, Fact, then running it as a goal.
Say I have the following:
person(james).
person(pete).
father(james, pete).
Is there a way to validate that both the arguments to father have been defined i.e to stop a typo such as father(jmes, pete).
There is an easy way of checking these kinds of errors using Prolog: You can call rules at initialization time, i.e. one that checks that your fathers relations is properly defined. This can be useful to catch those typo errors.
:- use_module(library(error)).
check_fathers :-
% Take an element of the father relation
(father(P, _); father(_, P)),
% Proceed, if P is not a person
\+ person(P),
% Throw an error
syntax_error(father_is_no_person(P)).
check_fathers.
:- check_fathers.
person(james).
person(pete).
father(jame, pete). % TYPO! jame instead of james
Then, the program will produce the following output:
ERROR: Syntax error: father_is_no_person(jame)
Warning: <filename>:<line>:
Warning: Goal (directive) failed: user:check_fathers
Your assumptions are wrong in this sense:
father(james, pete). is a fact. It is something that you tell the Prolog processor is uneniably true (similar to a row in a table in a relational database).
So is father(jmes, pete).. Another fact. You are stating that this is so.
There is nothing to check, really.
On the other hand, if father(jmes, pete) appears in a a goal position, the Prolog processor will say "no, I have no indiciation that this is true":
father(james, pete). % that's a fat fact!
?- father(jmes, pete). % that's a query
false. % and the answer is "no, there is no evidence of that"
What you you would like to have is to have something like Java enum types: have the compiler make sure that a keyword comes indeed from a selected set of allowed keywords.
Prolog has has only basic typing, so this cannot be done directly.
But you could do this:
% if X is an unbound variable or a member of the indicated list,
% we are good
allowed_father(X) :-
(var(X);memberchk(X,[james,vader])),!.
% otherwise, we don't just fail, we actually throw an exception
allowed_father(X) :-
throw(error(unknown_father(X))).
% ---
% if X is an unbound variable or a member of the indicated list,
% we are good
allowed_son(X) :-
(var(X);memberchk(X,[pete,luke])),!.
% otherwise, we don't just fail, we actually throw an exception
allowed_father(X) :-
throw(error(unknown_son(X))).
and then you can call the above predicates whenever you need to perform a check:
query_anout(Father) :-
allowed_father(Father),
...
But it's rather awkward. Plus the thrown exception is not ISO-standard and the resulting error message may be confusing (I always rage against ISO standard exceptions which are doubleplusungood awkward)
I'm trying to sort a list of lists by the third element in the sub-lists, and am doing so using a predicate for sorting defined as such:
sortData(X, [_,_,Z1], [_,_,Z2]) :- compare(X, Z1, Z2).
When I try to use this predicate in my Prolog console (predsort(sortData, [[0,5,2],[6,3,1]], X).), I get an error stating:
uncaught exception: error(existence_error(procedure,predsort/3),top_level/0)
I did some research and found this SO question on the matter, but was unable to use the tips suggested by the commenters to fix my error. I tried adding in :- use_module(library(sort)). to my code, but that gave a warning upon compilation (warning: unknown directive use_module/1 - maybe use initialization/1 - directive ignored).
Any tips as to why I may be getting the predsort/3 existence error?
EDIT: My desired output given the call above is: X = [[6, 3, 1], [0, 5, 2]].
NB: Just to be clear, my motivation for the question below is to learn my way around Prolog and SWI-Prolog, not to get past a particular error message. In fact, I already know one way to get past this error. My question asks about whether several other alternatives are also possible.
An exercise in my Prolog textbook asks one to describe the outcome one should expect from several queries, assuming one has consulted the following knowledgebase beforehand:
x(a).
z(b).
z(c).
z(d).
w(V) :- x(V).
w(V) :- y(V).
w(V) :- z(V).
On SWI-Prolog, at least, most of these queries fail, because SWI-Prolog intreprets y as undefined.
From the solutions to the exercises at the end of the book I can tell that this is not the authors' intended outcome. Maybe there's a Prolog implementation for which the exercise would turn as the solution presents it.
Be that as it may, I'd like to learn about good ways to work around the problem.
Consider, for example, the query w(x).. the book's solution claims that the query w(x). should evaluate to false.. In fact, this is what happens:
?- w(x).
ERROR: w/1: Undefined procedure: y/1
Exception: (7) y(x) ?
(At this point, SWI-Prolog is expecting me to enter some letter indicating how to respond to the exception. More about this later.)
I'm looking for ways to either turn the interaction above to
?- w(x).
false.
?-
...or at least for a suitable <ONE-LETTER RESPONSE> I could give to SWI-Prolog so that it arrives at the conclusion false. IOW, so that
?- w(x).
ERROR: w/1: Undefined procedure: y/1
Exception: (7) y(x) ? <ONE-LETTER RESPONSE>
false.
?-
I know of at least one answer to my question, namely simply to delete or comment out the line:
w(V) :- y(V).
I would like to know of other possible solutions, such as, for example, the "suitable " I alluded to earlier.
Another possibility would be some SWI-Prolog global configuration that would result in the above interaction to change to
?- w(x).
false.
?-
A third possibility would be to "define" y in some minimal way. The only way I can come up with is by adding the fact
y(dummy).
to the knowledgebase. Is there a more minimal way to define y, one that does not require introducing an extraneous constant into the domain of discourse?
(This is not specific to SWI)
The first Prolog systems back in the 1970s actually behaved in the way you describe. Soon it became apparent that this is a frequent source of errors. Simple misspellings remained undetected for too long. Current implementations produce a clean existence error. This is standard behaviour since 1995.
However, you can go back into the olden tymes with the ISO Prolog flag unknown which has three values error (default), fail, and warning.
?- inex.
ERROR: Undefined procedure: inex/0 (DWIM could not correct goal)
?- set_prolog_flag(unknown, fail).
Warning: Using a non-error value for unknown in the global module
Warning: causes most of the development environment to stop working.
Warning: Please use :- dynamic or limit usage of unknown to a module.
Warning: See http://www.swi-prolog.org/howto/database.html
true.
?- inex.
false.
?- set_prolog_flag(unknown, warning).
Warning: Using a non-error value for unknown in the global module
Warning: causes most of the development environment to stop working.
Warning: Please use :- dynamic or limit usage of unknown to a module.
Warning: See http://www.swi-prolog.org/howto/database.html
true.
?- inex.
Warning: toplevel: Undefined procedure: inex/0 (DWIM could not correct goal)
false.
As you can read above, SWI proposes to use a dynamic declaration in stead - which in turn has its own problems... It is much better to declare instead:
:- discontiguous(y/1).
An undefined procedure error raises an exception so if you want the exception to be raised because you don't want to change y/1 predicate (delete or define it) you need to catch the exception and then return false like this:
x(a).
z(b).
z(c).
z(d).
w(V) :- x(V).
w(V) :- catch(y(V), error(Err,_Context),my_handler(Err)).
w(V) :- z(V).
my_handler(Err):- write(Err),fail.
Example:
?- w(x).
existence_error(procedure,y/1)
false.
I am just starting to use Prolog, and already I've run into problem with a seemingly simple example. Here is my .pl file:
hacker(P) :- mountaindew(P), doesntsleep(P).
hacker(P) :- writesgoodcode(P).
writesgoodcode(jeff).
Then, after I load the program into swipl, I test it with this line at the prompt
writesgoodcode(jeff).
I thought it would display true, but I get this error:
?- hacker(jeff).
ERROR: hacker/1: Undefined procedure: mountaindew/1
Exception: (7) hacker(jeff) ?
This program works fine, but this doesn't solve my problems:
hacker(P) :- writesgoodcode(P).
writesgoodcode(jeff).
$ swipl -s dumb.pl
% dumb.pl compiled 0.00 sec, 1,112 bytes
?- hacker(jeff).
true.
Can anyone explain why my original program doesn't work? From my understanding, Prolog should "skip" the first statement since it doesn't have enough information, and check the next line. It does have enough info for that second line, and thus it should evaluate true. Any help or a point in the right direction would be great. Thanks.
As the error message says, you have an undefined procedure mountaindew/1. To make your code return true, your options are:
Define this predicate
Declare that this predicate is dynamic: dynamic(mountaindew/1)
Declare that all unknown predicates should fail (not recommended): set_prolog_flag(unknown, fail)
you could also change the order of the predicates (cannot be done always ofc)
but mostly what Kaarel said.
in the end there is not really a point in writing something that will always fail, even if you are still developing the code
This works but as I am a beginner I can't say why. The word "uninstantiated" may apply. Despite not knowing why it works, I think it's helpful to show one way that works.
hacker(P) :- mountaindew(P), doesntsleep(P).
hacker(P) :- writesgoodcode(P).
mountaindew(john).
doesntsleep(john).
writesgoodcode(jeff).