酷兔英语

章节正文

succeed
A Prolog goal succeeds if it is possible to either check it directly against the facts known to Prolog, or find bindings for variables in the goal that makes the goal true.

A query succeeds if each of its goals succeeds.

 

 

term
Syntactically, all data objects in Prolog are terms. For example, the atom mar and date and the structuredate(2004, mar, 21) are terms. So are the numbers 2004 and 21, for that matter. So in date(2004, mar, 21), the primary functor is date, the arity is 3, and the arguments are 2004, mar, and 21.

 

In general, a term of arity n can be an atom (the functor) followed by narguments, which will be enclosed in parentheses ( ) and separated by commas. Note that the arity might be 0, in which case there are no parentheses, commas, or arguments. A term can also be a number. Sometimes the term can use an infix operator like <, in which case the functor appears between the arguments (if the arity is 2) or before the argument but without parentheses (if the arity is 1).

term with components colour-coded

For + and (and occasionally?) signs in front of arguments, in procedure header comments, see comments.

term type testing, atom, atomic, compound, float, integer, nonvar, number, var

It may be useful to be able to test if a term is an number or a variable or something else. Prolog provides several such tests:

 

Goalsucceeds if X is ...
var(X)an uninstantiated variable
nonvar(X)not a variable, or is an instantiated variable
compound(X)a compound term - not an unbound variable, and not atomic (see below)
atom(X)an atom, or bound to an atom
integer(X)an integer, or bound to an integer
float(X)a floating point (fractional) number such as 3.5 or 1.0, or bound to one - but, if float(X) is evaluated using is, then you get thisfloat
number(X)a number, or bound to a number (integer or float)
atomic(X)a number, string, or atom, or bound to one

 

testing your code
Here are some tips on testing your Prolog code.
And here are some tips on writing recursive procedures in Prolog that include some tips on debugging (in example 3).

 

tracing
Tracing the execution of a Prolog query allows you to see all of the goals that are executed as part of the query, in sequence, along with whether or not they succeed. Tracing also allows you to see what steps occur as Prolog backtracks.

 

To turn on tracing in Prolog, execute the "goal"

?- trace.true.

When you are finished with tracing, turn it off using the "goal"

?- notrace.

 

Here is an example of trace in action. First some code, which computes factorial N - the product of the numbers from 1 to N. By convention, factorial 0 is 1. Factorial N is often written N!, where the exclamation mark signifies the "factorial operator". Here is the code:

 

factorial(0, 1).
factorial(N, NFact) :-
    N > 0,
    Nminus1 is N - 1,
    factorial(Nminus1, Nminus1Fact),
    NFact is Nminus1Fact * N.
rule 1
rule 2
rule 2, goal 1
rule 2, goal 2
rule 2, goal 3
rule 2, goal 4
factorial(0) = 1
 
if N > 0, then
compute N - 1,
recursively work out factorial(N-1),
then multiply that by N

 

The tables above and below may not display correctly if viewed in a narrow window. If the commentary doesn't seem to line up correctly with the text to the left of it, try making your browser window wider.

 

Prolog dialog/trace outputCommentary
prolog -s factorial.pl
blah blah blah ...
?- trace.true.
[trace]  ?- factorial(3, X).   Call: (7) factorial(3, _G284) ? creep*
^  Call: (8) 3>0 ? creep
^  Exit: (8) 3>0 ? creep
^  Call: (8) _L205 is 3-1 ? creep
^  Exit: (8) 2 is 3-1 ? creep
   Call: (8) factorial(2, _L206) ? creep
^  Call: (9) 2>0 ? creep
^  Exit: (9) 2>0 ? creep
^  Call: (9) _L224 is 2-1 ? creep
^  Exit: (9) 1 is 2-1 ? creep
   Call: (9) factorial(1, _L225) ? creep
^  Call: (10) 1>0 ? creep
^  Exit: (10) 1>0 ? creep
^  Call: (10) _L243 is 1-1 ? creep
^  Exit: (10) 0 is 1-1 ? creep
   Call: (10) factorial(0, _L244) ? creep
   Exit: (10) factorial(0, 1) ? creep
^  Call: (10) _L225 is 1*1 ? creep
^  Exit: (10) 1 is 1*1 ? creep
   Exit: (9) factorial(1, 1) ? creep
^  Call: (9) _L206 is 1*2 ? creep
^  Exit: (9) 2 is 1*2 ? creep
   Exit: (8) factorial(2, 2) ? creep
^  Call: (8) _G284 is 2*3 ? creep
^  Exit: (8) 6 is 2*3 ? creep
   Exit: (7) factorial(3, 6) ? creep
X = 6 ;   Redo: (10) factorial(0, _L244) ? creep
^  Call: (11) 0>0 ? creep
^  Fail: (11) 0>0 ? creep
   Fail: (9) factorial(1, _L225) ? creep
   Fail: (8) factorial(2, _L206) ? creep
   Fail: (7) factorial(3, _G284) ? creep
false.
[debug]  ?- notrace. % turn off tracing
true.
[debug]  ?- 
Invoke prolog, loading code for factorial
Greeting from Prolog
Turn on tracing
Call factorial
Trace echoes query, replacing X with a unique variable
Rule 2, Goal 1 (N > 0) is invoked
Goal 1 succeeds immediately
Rule 2, Goal 2 invoked to compute 3 - 1
and succeeds
Rule 2, Goal 3 is invoked: level 2 call to factorial(2, ...)
Goal 1 again for new call to factorial
Goal 1 succeeds
New version of goal 2
succeeds
Rule 2, Goal 3 is invoked: level 3 call to factorial(1, ...)
Goal 1 again
succeeds
Goal 2 again
successfully
Rule 2, Goal 3 is invoked: recursive call to factorial(0, ...)
This time, Rule 1 succeeds at once.
This is Goal 4 of level 3
Compute 1 * 1 without trouble
so the level 3 factorial call succeeds
This is goal 4 of level 2
Compute 1 * 2 without trouble
so the level 2 factorial call succeeds
This is goal 4 of level 1
Compute 2 * 3 without trouble
so the level 1 factorial call succeeds
... with this binding of X - type ";" to find more solutions
Prolog backtracks looking for another solution
without success
Turn off tracing.
* What is this "creep" business? In SWI Prolog, the implementation of Prolog which this dictionary uses for the syntax of its examples, when you press return at the end of a line of tracing, Prolog prints "creep" on the same line, and then prints the next line of trace output on the next line. Pressing return again produces "creep" again and another line of tracing, and so on.

 

There are further tracing facilities in SWI Prolog. Do

?- help(trace).
to start to find out about them.

 

Built-in Prolog functions are not traced - that is, the internals of calls to things like member are not further explained by tracing them.

 

true
Built-in Prolog predicate with no arguments, which, as the name suggests, always succeeds.

 

See also fail, repeat.

 

 

underscore, don't-care variable
The Prolog variable_ (underscore) is a "don't-care" variable, which will match anything (atom, number, structure, ...). For example, the rule

 

bad(Dog) :- bites(Dog, _).

says that something (Dog) is bad if Dog bites anything. The "anything" is represented by _. Unlike other variables in Prolog, a bare _ can match different things in the same rule. So, for example, if gives(From, To, Gift) is a three-place procedure that is true if From gives Gift to To, then

giver(X) :- gives(X, _, _).

signifies that someone (X) is a "giver" if X gives something to anybody - the two _ s don't have to match the same thing. So if gives(fred, john, black_eye). is stored in the Prolog database, then the rule above allows us to infer that fred is a giver.

To be more explicit about the meaning of your rule, you could instead write:

bad(Dog) :- bites(Dog, _Anybody).
This indicates what the _variable is actually representing, but has the feature that the binding of _Anybody typically doesn't get reported when Prolog finds a solution. In Prolog interpreters that report singleton variables (variables that are only used once in a rule - often these are caused by typographical errors in the code, which is why Prolog warns you about them) do not report singleton variables that begin with _. This is useful is you are trying to get rid of warning messages in your Prolog code.

 

The rule

bad(Dog) :- bites(Dog, _Anybody).
in fact has a bug, in the sense that the _Anybody will match things (like dogfood) that a dog might bite without being "bad". Maybe the rule should say instead:
bad(Dog) :-
    bites(Dog, Something),
    is_person(Something).
% add your own list of prohibitions - shoes, cats, ...

 

Prolog systems make internal use of variable names beginning with an underscore, e.g. _G157. These are not "don't-care" variables, but are chosen to not clash with any variable name a Prolog programmer is likely to use.

Underscores may also be used in the middle of variable or atom names, as in Intermediate_solution, likes_person - again, these are not "don't-care" variables. The idea is to make the variable or atom name more readable.

 



文章标签:词典  

章节正文