Debugging
Adesea dorim, atunci cand programul nu merge tocmai cum trebuie sa vedem cum sunt instantiate
variabilele in interogarile interne din cadrul regulilor. Pentru a evita afisarile de control
(folosirea write-urilor pentru diverse variabile ca sa vedem cum se schimba valorile)
putem folosi mecanismul de debugging oferit de prolog. Acesta se porneste cu predicatul
trace
.
Din acest moment orice interogare va incepe sa se realizeze pas de pas (afisandu-se etapele intermediare).
Pentru a trece de la un pas la altul se apasa pe enter.
Consideram exemplul cu suma de la un exercitiu anterior, la care am adaugat si o conditie de validitate a termenului
instantiat, si anume ca acesta sa fie numar.
suma(N, S):-number(N), N1 is N-1, suma(N1,S1), S is S1 + N.
Dupa consultarea programului, afisam clauzele cu predicatul listing, iar apoi pornim debuging-ul si incercam o interogare.
| ?- listing.
suma(0, 0).
suma(A, B) :-
number(A),
C is A-1,
suma(C, D),
B is D+A.
yes
| ?- trace.
% The debugger will first creep -- showing everything (trace)
yes
% trace
| ?- suma(3,S).
1 1 Call: suma(3,_351) ?
2 2 Call: number(3) ?
2 2 Exit: number(3) ?
3 2 Call: _797 is 3-1 ?
3 2 Exit: 2 is 3-1 ?
4 2 Call: suma(2,_807) ?
5 3 Call: number(2) ?
5 3 Exit: number(2) ?
6 3 Call: _3308 is 2-1 ?
6 3 Exit: 1 is 2-1 ?
7 3 Call: suma(1,_3318) ? a
% Execution aborted
| ?-
Liniile care incep cu Call se refera la o interogare interna. Termenii de forma _numar, cum e de exemplu _351
sunt neinstantiati. Prima linie se refera chiar la interogarea suma(3,S), Call: suma(3,_351)
, unde
_351 se refera de fapt la S.
Pe urmatorul rand este un nou call, Call: number(3)
, este o interogare interna, a primului predicat
aflat in clauza lui suma. Pe a 3-a linie se indica faptul ca s-a iesit cu succes (cu valoarea true),
Exit: number(3)
(daca s-ar fi terminat cu esec, atunci ar fi aparut mesajul Fail).
Urmatorul call, Call: _797 is 3-1
se termina cu succes dar si instantiaza _797 cu valoarea 2:
Exit: 2 is 3-1
.
Observati ca la final s-a dat comanda a
, pentru a se renunta la executie.
Vom vedea pentru acelasi cod si un exemplu de esec al unei interogari. Deoarece mai devreme s-a dat abort,
s-a iesit si din modul de debugging. Asa ca va trebui sa il repornim.
| ?- trace.
% The debugger will first creep -- showing everything (trace)
yes
% trace
| ?-
| ?- suma(abc,S).
1 1 Call: suma(abc,_351) ?
2 2 Call: number(abc) ?
2 2 Fail: number(abc) ?
1 1 Fail: suma(abc,_351) ?
no
% trace
| ?-
In exemplul de mai sus, se observa ca dupa ce se face Call: number(abc)
acesta se termina cu esec,
Fail: number(abc)
deoarece abc nu este numar, aceasta ducand si la terminarea cu fail a predicatului suma: Fail: suma(abc,_351)
.
Gasiti o lista completa cu comenzile acceptate in timpul debugging-ului in documentatia pentru sicstus prolog.
Trace-ul nu se opreste automat dupa ce se termina o interogare, el ramane activat si pentru interogarile
ulterioare.
Pentru a opri trace-ul fie se tasteaza a
in timpul afisarii detaliilor interogarii (cum s-a vazut mai sus),
fie se opreste cu ajutorul predicatului notrace
.
| ?- notrace.
1 1 Call: notrace ?
% The debugger is switched off
yes
| ?-
Deoarece debuggerul initial era pornit, el incepe si executia lui notrace tot in modul debugging, astfel se explica acel
Call: notrace
, dar dupa terminarea acestui apel trace-ul este oprit
(observati ca nici macar nu mai da un mesaj de exit).
Deblocarea consolei
In cazul in care interogarea unui predicat blocheaza consola si dorim sa-l intrerupem, folosim Ctrl+C, iar la aparitia mesajului Prolog interruption (h for help)? tastam a (de la abort). (Daca doriti sa vedeti si celelalte optiuni, tastati h, si, cum scrie si in mesaj, va va da toate comenzile posibile).
Tipuri de erori ce pot fi indicate de consola
O lista cu toate tipurile de erori ce pot fi intalnite in Sicstus Prolog gasiti in documentatia oficiala (observati ca pe pagina respectiva aveti la inceput un cuprins de linkuri catre fiecare tip de eroare).
Mai jos sunt enumerate tipurile de erori cu care e posibil sa va intalniti cel mai frecvent in teme.
-
Syntax error - Eroare de sintaxa, apare de exemplu cand consultati un fisier ori cand realizati in consola
o interogare scrisa gresit.
Exemplu:% consulting c:/documents and settings/userpc/desktop/temporar.pl...
! Syntax error
! operator expected after expression
! in line 24
! pred
! <<here>>
! ( a , b ) .
! Approximate lines: 23-25, file: 'c:/documents and settings/userpc/desktop/temporar.pl'
% consulted c:/documents and settings/userpc/desktop/temporar.pl in module user, 0 msec -88 bytes
yes
| ?-Observati in zona marcata cu galben faptul ca va da linia/liniile in care se gaseste eroarea, iar in zona marcata cu bleu va indica prin
<<here>>
locul anume unde considera ca s-a petrecut eroarea. -
Domain error -
Apare atunci cand un parametru de input are valori in afara domeniului permis, de exemplu impatire la 0,
sqrt(valori negative), expresii aritmetice ce contin atomi etc.
Exemple:| ?- a=:=3.
! Domain error in argument 1 of =:= /2
! expected expression, but found a
! goal: a=:=3
| ?-Observati ca pe al doilea rand afiseaza motivul pentru care s-a produs eroarea:
expected expression, but found a
| ?- X is 3/0.
! Domain error in argument 2 of is/2
! expected an integer not equal to 0, but found 0.0
! goal: _113 is 3/0
| ?-
-
Existence error -
Cum ii spune si numele un element apelat nu exista.
Exemplu: predicatul p cu 2 argumente nu a fost definit. Incercarea unei interogari referitoare la p/2 va genera o astfel de eroare:| ?- p(a,b).Alt exemplu:
! Existence error in user:p/2
! procedure user:p/2 does not exist
! goal: user:p(a,b)
| ?-| ?- consult(nu_exista).
! Existence error in argument 1 of consult/1
! file nu_exista does not exist
! goal: consult(user:nu_exista)
| ?-
-
Instantiation error -
Apare atunci cand se asteapta ca un anumit parametru sa fie instantiat si nu este.
Exemplu:| ?- X=:=8.
! Instantiation error in argument 1 of =:= /2
! goal: _111=:=8
| ?-
- Type error -
Apare cand asteapta un alt tip de date.
Exemplu:
Operatorul =.. necesita ca in operandul din dreapta sa existe intotdeauna un element de tip lista.| ?- X=..ceva.
! Type error in argument 2 of =.. /2
! expected list, but found ceva
! goal: _113=..ceva
| ?-
- Permission error -actiunea respectiva nu este permisa.
Exemplu:
Eroarea apare deoarece s-a incercat redefinirea lui bagof care este un predicat built-in( exista in cod o linie de formabagof(X,Y,Z):- X>3,Y>3,Z>0.
)% consulting c:/documents and settings/userpc/desktop/temporar.pl...Urmatoarea eroare apare pentru ca predicatul retract poate sterge doar clauze ale predicatelor dinamice.
! Permission error: cannot redefine built_in bagof/3
! Approximate lines: 23-26, file: 'c:/documents and settings/userpc/desktop/temporar.pl'
% consulted c:/documents and settings/userpc/desktop/temporar.pl in module user, 0 msec -88 bytes
| ?-| ?- retract(pred(a,b)).
! Permission error: cannot retract static user:pred/2
! goal: retract(user:pred(a,b))
| ?-
Warning-uri des intalnite
- Variabilele singleton, sunt variabilele care apar o singura data in cadrul unei reguli, practic din aceasta cauza
asupra lor nu exista nicio conditie, valoarea lor nu e importanta pentru regula cu pricina, si de aceea pot sa aiba numele
inlocuite cu _ , simbolul variabilei anonime. E bine sa fiti atenti la acest warning deoarece poate fi generat si de greseli
de scriere din neatentie
(de exemplu, cand vedeti ca Rez si REz sunt singleton intr-o regula...).
% consulting c:/documents and settings/userpc/desktop/temporar.pl...
* [Y] - singleton variables
* Approximate lines: 25-26, file: 'c:/documents and settings/userpc/desktop/temporar.pl'
% consulted c:/documents and settings/userpc/desktop/temporar.pl in module user,
0 msec 144 bytes
- Este indicat pentru un program ordonat sa aveti clauzele aceluiasi predicat grupate impreuna in program pentru o parcurgere mai
usoara, si pentru un stil ordonat. Daca aveti clauzele aceluiasi predicat separate de clauzele vreunui alt predicat veti primi un warning de forma:
% consulting c:/documents and settings/userpc/desktop/temporar.pl...
* clauses for user:pred/2 are not together
* Approximate lines: 26-27, file: 'c:/documents and settings/userpc/desktop/temporar.pl'
% consulted c:/documents and settings/userpc/desktop/temporar.pl in module user, 0 msec 0 bytes