酷兔英语

章节正文

infix and prefix predicates/procedures
Most built-in constructs in Prolog, and, by default, the procedures and terms that you write yourself, use prefix syntax - that is, the name of the term/procedure (the functor) precedes the arguments (which are surrounded by parentheses and separated by commas). For example, when we use the built-in predicate member, we write something like member(Item, [a, b, c]) - first the predicate name, member, then "(", then the first argument, Item, then a comma, then the second argument, [a, b, c], then ")".

 

However, with built-in predicates like =, < and > that are usually written between their arguments, as in First < Max, we write, in Prolog as in mathematics, in infix notation. Another infix built-in "predicate" is is, which is used in evaluating arithmetic expressions.

It is possible in Prolog to define your own infix (and postfix) operators, and modify the syntactic handling of prefix operators - see op.

 

input in Prolog, read, end_of_file, get, get_byte, getc, flush_output
Input in Prolog is not always needed, as often the query process provides all the input that is needed. If explicit input is required, a set of extra-logical built-in predicates is available. These include:

 

 

  • read(X) which reads the next term in the current input stream, which means the window on your workstation unless you have done something slightly fancy with files, and unifies it with the variableX.

     

     

  • end_of_file: if there is nothing to read in the current input stream, read(X) causes X to be bound to the special symbolend_of_file. Unless you are absolutely sure you have some other way of knowing when there will be no more input data to read, you should check to make sure that the term that you have read is not end_of_file. Ways that you might be (almost) absolutely sure: the first term read might be a number indicating how many further terms are to be read.

     

     

  • get_byte(C) which reads a single character from the current input stream, and binds the equivalent integer code, in the range 0 to 255. If there is no further character to read, C is bound to –1.

     

     

  • get(C) is like get_byte(C), except that it reads the first non-blank character, if any, from the current input stream.

     

     

  • flush_output is actually an output goal, which ensures that any output which has been requested but not yet performed, is performed right now. Output might not be completed until there is enough to make it worthwhile, or until an operation like flush_output forces it.

     

Example 1: Assume that input is coming from the user's workstation window and that procedureread_a_char is defined as:

read_a_char(C) :-
   write('Type: '), flush_output,
   get_byte(C).

Then you can do the following - note that 43 is the character code for the character+.

?- read_a_char(Ch).
Type: +
Ch = 43

See also atom_codes, for conversion of a string of numeric character codes to an atom composed of the characters represented by those character codes. For example, 102, 105, 100, and 111 are the numeric codes for the letters f, i, d, and o. atom_codes can be used as follows:

?- atom_codes(A, [102, 105, 100, 111]).
A = fido

Example 2: Assume that there is a file called inputdata, which contains on its first line the term
likes(mary, pizza).
with a full stop at the end of the term.

?- see('inputdata'), read(Term), seen.
Term = likes(mary, pizza)

NB: No full stop at the end of Term's binding.

 

input schema
In any programming language, it is possible to specify schemata that how to code common programming tasks. The following is a schema for reading material from a file and processing it

 

dountilstop :-
  repeat,
  read(X),
  (X = stop, !
   ;
   process(X),
   fail
  ).

In this case, the code reads data, a term at a time, from the current input stream. To make that input stream a file called, say, inputdata, you would invoke the code as follows:

?- see('inputdata'), dountilstop, seen.

The call to fail is there to force backtracking. The call to repeat is there to force the code to endlessly repeat - that is, until something terminates the backtracking. This "something" is the cut after X = stop - if the term read is the atom stop, the goal X = stop succeeds, the cut is executed, and the rule terminates.

To use the schema, replace the read operation with the one you want (might be getc or ratom or ...), replace the call to process with a call to a procedure that does whateveryou want to do to the data, and you're in business. Actually - you'll probably find a few other adjustments are needed, but at least you're on the right track.

See also read, repeat, see, seen, ; (or), and fail.

 

is, evaluation
The is built-in predicate is used in Prolog to force the evaluation of arithmetic expressions. If you just write something like X = 2 + 4, the result is to bind X to the unevaluated term 2 + 4, not to 6. Example:
     ?- X = 2 + 4.     X = 2+4

 

If instead you write X is 2 + 4, Prolog arranges for the second argument, the arithmetic expression 2 + 4, to be evaluated (giving the result 6) before binding the result to X.

     ?- X is 2 + 4.     X = 6

 

It is only and always the second argument that is evaluated. This can lead to some strange-looking bits of code, by mathematical standards. For example, mod is the remainder-after-division operator, so in Prolog, to test whether a number N is even, we write 0 is N mod 2, rather than the usual mathematical ordering: N mod 2 = 0.

What is the difference between N = 1 and N is 1? In final effect, nothing. However, with N is 1, Prolog is being asked to do an extra step to work out the value of 1 (which, not surprisingly, is 1). Arguably, it is better to use N = 1, since this does not call for an unnecessary evaluation.

The message is: useisonly when you need to evaluate an arithmetic expression.

Actually, you don't need to use is to evaluatearithmetic expressions that are arguments to the arithmeticcomparison operators >, >=, < =<, =:= (equal), and == (not equal), all of which automatically evaluate their arguments.

Note the syntax of is: either
<variable> is <expression>
or
<numeric constant> is <expression>
Thus things like X*Y is Z*W do not work, as X*Y is an expression, not a variable - use either

0 is X*Y - Z*W
or
X*Y =:= Z*W
instead.

 

A common mistake, for people used to procedural programming languages like C and Java, is to try to change the binding of a variable by using an goal like N is N + 1. This goal will never succeed, as it requires N to have the same value as N + 1, which is impossible. If you find yourself wanting to do something like this, you could look at the code for factorial in the article on tracing for inspiration.

Another common mistake is to try a goal involving is before the variable(s) on the right-hand side of the is has/have been instantiated. Prolog cannot evaluate an arithmetic expression if it doesn't know the values of variables in the expression. This is why the following example fails:

?- X is Y + 1, Y = 3.
ERROR: is/2: Arguments are not sufficiently instantiated
Compare this with:
?- Y = 3, X is Y + 1.
Y = 3,
X = 4.

 

 

 

lists, [Head | Tail], .(Head, Tail)
A list in Prolog is written as a comma-separated sequence of items, between square brackets. For example, [1, 2, 3] is a list.

 

The empty list is written [].

A list with just a single item, say the number 7, is written [7].

Frequently it is convenient to refer to a list by giving the first item, and a list consisting of the rest of the items. In this case, one writes the list as [First | Rest]. Note that Restmust be a list, while Head need not be.

We have expressed this here using variables, but this need not be so, for example, we could write [1, 2, 3] as:

  • [1 | [2, 3]]
  • [1 | Rest], where Rest is bound to [2, 3]
  • [First | [2, 3]], where First is bound to 1
  • [First | Rest], where First is bound to 1, and Rest is bound to [2, 3]
  • [1, 2 | [3]]
  • [1, 2, 3 | []]
and many more possibilities.

 

You should always write your Prolog list in the most compactreasonable format. So for example, while [X | []] is the same list as [X], the second version is much easier to read, so you should use it.

It is possible to have lists of lists, or lists some of whose members are themselves lists:

 

Lists can also be expressed using a normal term syntax, using the built-in predicate name . - that is, a full stop or period. In this case, the empty list atom ([]) must be used to terminate the list. However, this approach is more cumbersome, and in practice people use the [1, 2, 3]- style syntax. Example:

?- X = .(1, .(2, .(3, []))).
X = [1, 2, 3]


文章标签:词典  

章节正文