gprolog: Getting a stacktrace after an exception - debugging

While using gprolog I often have exceptions without any kind of line numbers or context like this one:
uncaught exception: error(instantiation_error,(is)/2)
Without any kind of context. I know I can do a trace but it would take very long to debug it with trace since I need to execute a lot of things before getting to the place where the error occur.
Any idea on how to have this stacktrace ? Or a dynamic trace / notrace ?
EDIT: Or just automate the printing of the whole trace output.

#gusbro's answer (s(X)) shows you how you somewhat solve this with GNU's debugger. However, if you cannot afford to see all the printing going on, or it is much too slow, you might consider the following "debugger" available as library(debug) in Scryer.
I personally do not use debuggers offered by Prolog systems for the simple reason that most of them print much too much, are often buggy themselves, and have their own specific ever changing conventions, I can't afford to learn.
:- op(900, fx, [#,$,$-]).
$-(G_0) :-
catch(G_0, Ex, ( portray_clause(exception:Ex:G_0), throw(Ex) ) ).
$(G_0) :-
portray_clause(call:G_0),
$-G_0,
portray_clause(exit:G_0).
#(G_0) :-
( $-G_0
*-> true
; portray_clause(badfail:G_0),
throw(goal_failed(G_0))
).
:- op(950, fy, *).
*(_).
To use it, simply add $-, $, or # in front of a specific goal.
$- means: only signal exceptions going through this goal
$ additionally show call and exit
# assures that there is at least one answer, and if not, it is reported and an exception is thrown.
Use above annotations sparingly!
* removes the goal. This is for generalizing a program doing program modification/program-slicing in a pure monotonic program. You need this in case of unexpected failures. For examples how to use it, see the following answers/debugging sessions
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13.
More.
_/*term*/ replaces a term by an anonymous variable. This generalizes a program even further than * alone. Example sessions:
1,
2,
3,
4,
5,
6,
7,
8,
9,
10.
In this manner you can reduce the information you watch significantly.
In other systems supporting meta_predicate directives like SICStus, YAP and SWI, add in front the following directive:
:- meta_predicate(( $-(0), $(0), #(0) )).

You may trace/0 and leash/1 only the exception port, e.g:
?- trace.
?- leash([exception]).
Then you run your program and it will print a trace on screen but only stop when an exception occurs. There you can see the "stack trace" (ancestors) by pressing letter g.

Related

Find the exit to the labyrinth

I have to find the exit path to this labyrinth.
The labyrinth must be represented with connect events eg connect(1,7), connect(2,8) etc.
The output path must be a list with start on the left edge and finish on the right edge.
I have written the following code:
connect(start,2).
connect(1, 7).
connect(7, 13).
connect(13, 14).
connect(14,15).
connect(15,21).
connect(14,20).
connect(20,26).
connect(26,27).
connect(27,28).
connect(28,29).
connect(23,29).
connect(17,23).
connect(11,17).
connect(5,11).
connect(5,6).
connect(19,25).
connect(25,31).
connect(31,32).
connect(32,33).
connect(33,34).
connect(34,35).
connect(35,36).
connect(12, 18).
connect(18, 24).
connect(24,30).
connect(30,36).
connect(2, 8).
connect(2,3).
connect(3,4).
connect(8,9).
connect(3, 9).
connect(4,10).
connect(10,16).
connect(16, 22).
connect(21, 22).
connect(32,finish).
I have stuck to the commands needed for finding the path.
Let's start from a smaller one.
We represent it as
connect(2,8).
connect(3,2).
connect(3,exit).
connect(3,9).
connect(8,9).
cango(A,B) :- connect(A,B).
cango(A,B) :- connect(B,A).
And program it as simply as possible,
path( Start, [Start | Path]) :-
Start = exit, Path = [].
path( Start, [Start | Path]) :-
cango( Start, Next),
path( Next, Path).
and that's it. And it even works,
3 ?- path(2,P).
P = [2, 3, exit] ;
P = [2, 3, exit, 3, exit] ;
P = [2, 3, exit, 3, exit, 3, exit] ;
P = [2, 3, exit, 3, exit, 3, exit, 3, exit] .
Wait, no, it doesn't. It gets stuck, with the above facts as shown, and doesn't even produce the first possible path, let alone avoiding this unwelcome repetitiveness.
But it did, when I tried it with a different set of connect facts -- and then I made a change, but a very small one, that broke this program. Yet the above set of connect facts does correctly describe the labyrinth...
All you need to do to make it work again is swap the arguments to one connect fact above. Try it. Does it produce any results now? Does it produce the same Path result as the one shown above, when we call it as path(2,Path)?
Then try swapping the order of the connect facts to get the same Path as shown above.
Then change the program so that it is impervious to such small differences in representation, and works for any set of facts that correctly describe the situation, not just such that was made specifically so the above simple program doesn't get stuck.
Then / or, change it so it produces all possible paths in order of their length.
Then change it so it produces the shortest path.
There, a whole learning program / path ahead of you.

Problems with library(lambda), currying and SWI Prolog

So I run into some troubles while (ab?)using
lambda.pl.
I do a "use_module(library(lambda))."
in the first lines of a file that
I consult via ["a.prolog"].
Then I get an "undefined procedure ()/3"
and some gibberish afterwards.
The same happens for any order of use_modules.
It happens whether I load a.prolog via
[...], consult or as a script from the cmdline.
I reduced the script to the currying-example from Rosseta code
https://rosettacode.org/wiki/Currying#Prolog
use_module(library(lambda)).
:- initialization(main, main).
main :-
N = 5, F = \X^Y^(Y is X+N), maplist(F, [1,2,3], L),
print(L).
It doesn't work.
It works, however, if I a manually load 'lambda'
at the swipl-prompt and immeditately consult
a.prolog. Then the goal N=5,.... works just fine.
If I, however, first consult a.prolog; then manually
use_module and then run the query, I get the error.
Reconsulting doesn't help onwards.
Somehow, the first command at the prompt needs to
be use_module.
Or do I get the loading mechanism completely wrong?
If so, please apologize; but I would love get a
hint how to solve this.
This is a common error when first using modules.
Please have a look at this line:
use_module(library(lambda)).
This is just a fact, saying "use_module(library(lambbda)) holds".
What you want instead is a directive.
A directive is a term with primary functor (:-)/1. That is, you want:
:- use_module(library(lambda)).
EDIT: For the particular case of library(lambda), I would like to add that there is a page with a lot of useful information about it that is a bit hard to find:
http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/ISO-Hiord
"Hiord" stands for higher order.

predsort/3 existence_error [Prolog]

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]].

Prolog gives is_absolute_file_name unhandled exception

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).

Using the prolog format predicate to print to file

Is it possible to use the prolog format predicate to print to file?
I have a table of data that I print to stdout using the format predicate, i.e.
print_table :-
print_table_header,
forall(range(1.0,10.0,0.1,N), print_row(N,L)).
%% print_row(L) :- take a list of the form, [a,b,c,d,e] and
%% print it to screen as a single row of tab separated float values (1DP)
print_row(N,L) :-
build_row(N,L),
format('~t~1f~10+ ~t~1f~10+ ~t~1f~10+ ~t~1f~10+ ~t~1f~10+ ~n', L).
print_table_header :-
format('~t~w~10+ ~t~w~10+ ~t~w~10+ ~t~w~10+ ~t~w~10+ ~n', ['N','N2','N3','N4','N5']).
would be nice to somehow reuse the code to print the same thing to file.
In addition to the other good answer (+1!), I would like to present a purer solution to such tasks.
The key idea is to make format/2 accessible within DCGs, and then to use a DCG to describe the output.
This is very easy, using the codes argument of format/3, provided by several Prolog implementations. All you need are the following short auxiliary definitions:
format_(Data, Args) --> call(format_dlist(Data, Args)).
format_dlist(Data, Args, Cs0, Cs) :- format(codes(Cs0,Cs), Data, Args).
The nonterminal call//1 calls its argument with two additional arguments that let you access the implicit DCG arguments, and this is used to describe additional codes via format/3.
Now, we can simply use the nonterminal format_//2 within DCGs.
For example, to describe a simple table:
table -->
row([a,b,c]),
row([d,e,f]).
row(Ls) --> format_("~t~w~10+~t~w~10+~t~w~10+~n", Ls).
Usage example and result:
?- phrase(table, Cs), format("~s", [Cs]).
a b c
d e f
Cs = [32, 32, 32, 32, 32, 32, 32, 32, 32|...].
Note that one last remaining format/2 is used to actually write the output to the screen.
However, everything else is free of side-effects and declaratively describes a table.
An important advantage of this method is that you can easily write test cases to see whether your tables are (still) correctly formatted. It is easy to reason about Prolog lists of codes (described with a DCG), but quite hard to reason about things that only appear on the terminal.
You can!
Consider the following extract of the SICStus Prolog documentation for format/[2,3]:
11.3.85 format/[2,3]
Synopsis
format(+Control, +Arguments)
format(+Stream, +Control, +Arguments)
Interprets the Arguments according to the Control string and prints the result on Stream.
The predicates format/[2,3] are widely supported across Prolog implementations.
However, as of right now, these predicates are not part of ISO Prolog.
I would write the output 'routines' with an additional parameter, a Stream, and then I would pass user while testing or printing to screen. See ISO predicates open/3, close/1 etc for stream handling...
Note that IO it's among the least 'declarative' areas of the language, because, for efficiency, an approach based on side effects is required...
SWI-Prolog has a builtin with_output_to, that would allows to reuse your existing code without adding a parameter. But since you tagged iso-prolog your question, you should really add the Stream parameter...

Resources