Common Prolog provides a standard 4-port debugging model (call
exit
redo
fail
).
Tracing, Spy Points, Leashing, and Interactive Debugging are each discussed separately in this section.
Exhaustive tracing is available with Common Prolog through the use of: (trace)
. After executing (trace)
, all goals will be displayed until control is returned to the top level loop, nodebug
is executed or notrace
is executed.
You can turn on tracing for backward chaining from Lisp by running:
(clog:logic '(and (clog:unleash) (trace)))
There are no command line tools for tracing forward chaining rules directly, but the RHS of each rule is run using a backward chaining rule with the same name, so they also appear when you trace backward chaining.
You could also add tracing to forward rules by defining a Meta Rule Protocol, for example like the explanation facility described in 6.1.1.3 A Simple Explanation Facility.
Spy points are the most important debugging facility in Common Prolog. They are used in the same way trace is used in Lisp. After executing (spy foo)
, all events associated with satisfying foo
goals will be traced and the user will enter a debugging command loop at every port (see A.7.4 Interactive Debugging below). A user can also specify (spy (foo 3))
, (spy (foo bar))
, or (spy ((foo 3) bar))
to place spy points on foo
goals with arity 3, on all predicates for foo
and bar
, or on foo
with arity 3 and all predicates for bar
respectively. Spy points are turned off with (nospy <spypoints>)
. If no spy points are mentioned, nospy
will turn off all spy points.
Leashing allows the user to control execution while tracing for goals that are not spied. Spied goals cause execution to enter a debugging command loop whenever they are reached. Leashing provides the same functionality for unspied goals. A user may choose to enter a debugging command loop at any subset of ports by using (leash events)
where events may be: call
, redo
, exit
or fail
. Leashing may be turned off using (unleash)
.
When Common Prolog execution enters a debugging command loop, the user has many options, which may be listed with ?
, for example:
|==> (spy member) | |((MEMBER 2)) |YES. |OK. | |==> (member 3 ?x) | |[1] CALL: (MEMBER 3 ?0)? ? <- user types ? | |(c)reep - turn on exhaustive tracing |(s)kip - skip until another port is | reached for this goal |(l)eap - turn off tracing until a spy | point or this goal is reached |(b)reak - enter a recursive | read/query/print loop |(d)isplay - display a listing for the | current goal |(q)uit - quit to top level |(r)etry - try to satisfy this goal again |(f)ail - cause the current goal to fail |(a)bort - exit Common Prolog |? - display this information | |? | |In a little more detail... | |creep - causes exhaustive tracing of the | next goal |skip - ignores spy points and executes | without displaying anything until | this goal is reached again | either at an exit, fail, | or redo port |leap - turns off exhaustive tracing until | a spy point or this goal is | reached |break - enters a recursive interpreter loop | so that the user may query | values, redefine a predicate, etc. |display - uses "listing" to display the | listing of the current goal |quit - returns to the top level interpreter | loop |retry - causes execution to return to the | call port of this goal as if | this goal had just been reached for | the first time. |fail - causes execution to jump to the fail | port of this goal |abort - completely exit Common Prolog
Continuing the example:
|d <- user selects display | |Compiled procedure: | |(DEFREL MEMBER | ((MEMBER ?X (?X . ?))) | ((MEMBER ?X (? . ?Y)) (MEMBER ?X ?Y))) ? c | ...user selects creep
|[1] EXIT: (MEMBER 3 (3 . ?0))? r | ...user selects retry | |[1] CALL: (MEMBER 3 ?0)? f <-user selects fail | |[1] FAIL: (MEMBER 3 ?0)? r <- one more time | |[1] CALL: (MEMBER 3 ?0)? s <- skip | |[1] EXIT: (MEMBER 3 (3 . ?0))? l <- leap
|?X = (3 . ?0); <- more solutions | |[1] REDO: (MEMBER 3 (3 . ?0))? c <- creep | |[2] CALL: (MEMBER 3 ?0)? b <- break | | |==> (nospy) | |NIL <- current spylist |YES. |OK. | |==> (halt) <- return to original execution |? l <- leap | |?X = (?0 3 . ?1)<cr> | |OK.
Another example:
|==> (defrel reverse | ((reverse () ())) | ((reverse (?x . ?y) ?z) | (reverse ?y ?w) | (append ?w (?x) ?z))) |<noise..> | |?X = ?0 |?Y = ?1 |?Z = ?2 |?W = ?3 | |OK.
|==> (defrel append | ((append () ?x ?x)) | ((append (?u . ?x) ?y (?u . ?z)) | (append ?x ?y ?z))) |<noise..>
|?X = ?0 |?U = ?1 |?Y = ?2 |?Z = ?3 | |OK.
|==> (unleash) | |YES. |OK. | |==> (trace) | |YES. |OK.
|==> (reverse (1 2 3) ?x) | |[1] CALL: (REVERSE (1 2 3) ?0) |[2] CALL: (REVERSE (2 3) ?0) |[3] CALL: (REVERSE (3) ?0) |[4] CALL: (REVERSE NIL ?0) |[4] EXIT: (REVERSE NIL NIL) |[5] CALL: (APPEND NIL (3) ?0) |[5] EXIT: (APPEND NIL (3) (3)) |[3] EXIT: (REVERSE (3) (3)) |[6] CALL: (APPEND (3) (2) ?0) |[7] CALL: (APPEND NIL (2) ?0) |[7] EXIT: (APPEND NIL (2) (2)) |[6] EXIT: (APPEND (3) (2) (3 2)) |[2] EXIT: (REVERSE (2 3) (3 2)) |[8] CALL: (APPEND (3 2) (1) ?0) |[9] CALL: (APPEND (2) (1) ?0) |[10] CALL: (APPEND NIL (1) ?0) |[10] EXIT: (APPEND NIL (1) (1)) |[9] EXIT: (APPEND (2) (1) (2 1)) |[8] EXIT: (APPEND (3 2) (1) (3 2 1)) |[1] EXIT: (REVERSE (1 2 3) (3 2 1)) |?X = (3 2 1);
|[1] REDO: (REVERSE (1 2 3) (3 2 1)) |[8] REDO: (APPEND (3 2) (1) (3 2 1)) |[9] REDO: (APPEND (2) (1) (2 1)) |[10] REDO: (APPEND NIL (1) (1)) |[10] FAIL: (APPEND NIL (1) ?0) |[9] FAIL: (APPEND (2) (1) ?0) |[8] FAIL: (APPEND (3 2) (1) ?0) |[2] REDO: (REVERSE (2 3) (3 2)) |[6] REDO: (APPEND (3) (2) (3 2)) |[7] REDO: (APPEND NIL (2) (2)) |[7] FAIL: (APPEND NIL (2) ?0) |[6] FAIL: (APPEND (3) (2) ?0) |[3] REDO: (REVERSE (3) (3)) |[5] REDO: (APPEND NIL (3) (3)) |[5] FAIL: (APPEND NIL (3) ?0) |[4] REDO: (REVERSE NIL NIL) |[4] FAIL: (REVERSE NIL ?0) |[3] FAIL: (REVERSE (3) ?0) |[2] FAIL: (REVERSE (2 3) ?0) |[1] FAIL: (REVERSE (1 2 3) ?0) |NO.
KnowledgeWorks and Prolog User Guide (Unix version) - 01 Dec 2021 19:35:52