Manual: Input and Output


Quintus Prolog Manual


(PREV) (NEXT)

G-7: Input and Output

G-7-0: Introduction

Prolog provides two classes of predicates for input and output: those which handle individual characters, and those which handle complete Prolog terms.

The following predicates have been added for I/O at the Prolog level:

at_end_of_file/[0,1] at_end_of_line/[0,1] open/4 seek/4 peek_char/[1,2] skip_line/[0,1] prompt/3 write_term/[1,2] read_term/[2,3]

Input and output happen with respect to streams. Therefore, this chapter discusses predicates which handle files and streams in addition to those which handle input and output of characters and terms.

In Quintus Prolog Release 3, the I/O system has been redesigned. Streams are now record based by default, for an increase in efficiency and portability. This leads to increased efficiency in opening streams, putting characters, flushing output, and in character I/O operations involving lines (end of line, new line, skipping lines). For a description of the new model, see section I-5-2. Combining Prolog and C I/O operations on the same stream is facilitated by a more complete set of functions.

G-7-1: About Streams

A Prolog stream can refer to a file or to the user's terminal


Footnote: At the C level, you can define more general streams, e.g., referring to pipes or to encrypted files (see section I-5-7-2
.)
. Each stream is used either for input or for output, but not for both. At any one time there is a current input stream and a current output stream. Input and output predicates fall into three categories:
  1. those which use the current input or output stream;
  2. those which take an explicit stream argument;
  3. those which use the standard input or output stream -- these generally refer to the user's terminal. Their names begin with 'tty'.

Initially, the current input and output streams both refer to the user's terminal. Each input and output built-in predicate refers implicitly or explicitly to a stream. The predicates which perform character and term I/O operations come in pairs such that (A) refers to the current stream, and (B) specifies a stream.


             'predicate_name'/n                  (A)
             'predicate_name'/n+1                (B)

Tip: Deciding which version to use involves a trade-off between speed and readability of code: In general, version (B), which specifies a stream, runs slower than (A). So it may be desirable to write code which changes the current stream and uses version (A). However, the use of (B) avoids the use of global variables and results in more readable programs.

G-7-1-1: Stream Categories

Quintus Prolog streams are divided into two categories, those opened by see/1 or tell/1 and those opened by open/[3,4]. A stream in the former group is referred to by its file specification, while a stream in the latter group is referred to by its stream object (see Figure G-7-1). For further information about file specifications, see Chapter G-6. Stream objects are discussed in section G-7-6-1. Reading the state of open streams is discussed in section G-7-7.

Each operating system permits a different number of streams to be open. For more information on this, refer to Chapter B-4.

G-7-2: Term Input

Term input operations include:

G-7-2-1: Reading Terms: The 'Read' Predicates

The 'Read' predicates are

read(-Term) read(+Stream, -Term) read_term(+Options, -Term) read_term(+Stream, +Options, -Term)

read_term/[2,3] offers many options to return extra information about the term.

When Prolog reads a term from the current input stream the following conditions hold:

G-7-2-2: Changing the Prompt

To query or change the sequence of characters (prompt) that indicates that the system is waiting for user input, call prompt/[2,3].

This predicate affects only the prompt given when a user's program is trying to read from the terminal (for example, by calling read/1 or get0/1). Note also that the prompt is reset to the default "|: " on return to the top level.

G-7-3: Term Output

Term output operations include:

G-7-3-1: Writing Terms: the 'Write' Predicates

write(+Stream, +Term) write(+Term) writeq(+Stream, +Term) writeq(+Term) write_canonical(+Term) write_canonical(+Stream, +Term) write_term(+Stream, +Term, +Options) write_term(+Term, +Options)

write_term/[2,3] is a generalization of the others and provides a number of options.

G-7-3-2: Common Characteristics

The output of the 'Write' predicates is not terminated by a full-stop; therefore, if you want the term to be acceptable as input to read/[1,2], you must send the terminating full-stop to the output stream yourself. For example,


             |?- write(a),
             put(0'.),
             nl.

If Term is uninstantiated, it is written as an anonymous variable (an underscore followed by a non-negative integer).

write_canonical[1,2] is provided so that Term, if written to a file, can be read back by read/[1,2] regardless of special characters in Term or prevailing operator declarations.

G-7-3-3: Distinctions Among the 'write' Predicates

G-7-3-4: Displaying Terms

Like write_canonical, display/1 ignores operator declarations and shows all compound terms in standard prefix form. For example, the command


         | ?- display(a+b).

produces the following:

         +(a,b)

Calling display/1 is a good way of finding out how Prolog parses a term with several operators. Unlike write_canonical/[1,2], display/1 does not put quotes around atoms and functors.

G-7-3-5: Using the 'portray' hook

print/1 is called from within the system in two places:

  1. to print the bindings of variables after a question has succeeded
  2. to print a goal during debugging

By default, the effect of print/1 is the same as that of write/1, but you can change its effect by providing clauses for the hook predicate portray/1.

If X is a variable, then it is printed using write(X). Otherwise the user-definable procedure portray(X) is called. If this succeeds, then it is assumed that X has been printed and print/1 exits (succeeds). Note that print/1 always calls portray/1 in module 'user'. Therefore, to be visible to print/1, portray/1 must either be defined in or imported into module 'user'.

If the call to portray/1 fails, and if X is a compound term, then write/1 is used to write the principal functor of X and print/1 is called recursively on its arguments. If X is atomic, it is written using write/1.

When print/1 has to print a list, say [X1,X2,...,Xn], it passes the whole list to portray/1. As usual, if portray/1 succeeds, it is assumed to have printed the entire list, and print/1 does nothing further with this term. Otherwise print/1 writes the list using bracket notation, calling print/1 on each element of the list in turn.

Since [X1,X2,...,Xn] is simply a different way of writing .(X1,[X2,...,Xn]), one might expect print/1 to be called recursively on the two arguments X1 and [X2,...,Xn], giving portray/1 a second chance at [X2,...,Xn]. This does not happen; lists are a special case in which print/1 is called separately for each of X1,X2,...Xn.

If you would like lists of character codes printed by print/1 using double-quote notation, you should include library(printchars) (described in Part K) as part of your version of portray/1.

Often it is desirable to define clauses for portray/1 in different files. This can be achieved either by declaring it multifile in each of the files, or by using library(add_portray).

G-7-3-6: Portraying a Clause

If you want to print a clause, portray_clause/1 is almost certainly the command you want. None of the other term output commands puts a full-stop after the written term. If you are writing a file of facts to be loaded by compile/1, use portray_clause/1, which attempts to ensure that the clauses it writes out can be read in again as clauses.

The output format used by portray_clause/1 and listing/1 has been carefully designed to be clear. We recommend that you use a similar style. In particular, never put a semicolon (disjunction symbol) at the end of a line in Prolog.

G-7-4: Character Input

G-7-4-0: Overview

NOTE: For compatibility with DEC-10 Character I/O a set of predicates are provided which are similar to the primary ones except that they always use the standard input and output streams, which normally refer to the user's terminal rather than to the current input stream or current output stream. They are easily recognizable as they all begin with "tty". Given stream-based input/output, these predicates are actually redundant. For example, you could write get0(user, C) instead of ttyget0(C). This note applies to the character output as well (section G-7-5).

The operations in this category are:

G-7-4-1: Reading Characters

get0(N) unifies N with the ASCII code of the next character from the current input stream. Cf. ttyget0/1.

get(N) unifies N with the ASCII code of the next non-layout character from the current input stream. Layout characters are all outside the inclusive range 33..126; this includes space, tab, linefeed, DEL, and all control characters. Cf. ttyget/1.

G-7-4-2: Peeking

Peeking at the next character without consuming it is useful when the interpretation of "this character" depends on what the next one is. Use peek_char/[1,2].

G-7-4-3: Skipping

There are two ways of skipping over characters in the current input stream: skip to a given character, or skip to the end of a line (or record).

G-7-4-4: Finding the End of Line and End of File

To test whether the end of a line on the end of the file has been reached on the current or specified input stream, use at_end_of_line/[0,1] or at_end_of_file/[0,1].

G-7-5: Character Output

The character output operations are:

Note: The note about "tty-" predicates at the beginning of section G-7-4 applies here as well.

G-7-5-1: Writing Characters

put(N) writes N to the current output stream or put(Stream, N) writes N to a specified one, Stream. N should be a legal ASCII character code or an integer expression.

If N evaluates to an integer, the least significant 8 bits are written.

The character is not necessarily printed immediately; they may be flushed if the buffer is full. See section G-7-6-9.

Cf. ttyput/1.

G-7-5-2: New Line

nl and nl(Stream) terminates the current output record on the current output stream or on a specified one, Stream. If the stream format is delimited (lf) or delimited (tty) (default format on Unix platform), a linefeed character (ASCII) is printed.

Cf. ttynl/0.

G-7-5-3: Tabs

tab(N) writes N spaces to the current output stream. N may be an integer expression.

The spaces are not necessarily printed immediately; see section G-7-6-9.

Cf. ttytab/1

G-7-5-4: Formatted Output

format(Control, Arguments) interprets the Arguments according to the Control string and prints the result on the current output stream. A stream can be specified using format/3.

This is used to produce output like this, either on the current output or on a specified stream:


        | ?- toc(1.5).
        Table of Contents                                               i


                           Table of Contents

1. Documentation supplement for Quintus Prolog Release 1.5 ........... 2

   1-1 Definition of the term "loaded" ............................... 2
   1-2 Finding all solutions ......................................... 3
   1-3 Searching for a file in a library ............................. 4
   1-4 New Built-in Predicates ....................................... 5
       1-4-1 write_canonical (?Term) ................................. 5
                    .
                    .
                    .
   1-7 File Specifications .......................................... 17
       1-7-1 multifile(+PredSpec) ................................... 18

yes

For details, including the code to produce this example, see the example program in the reference page for format/[2,3]. The character escaping facility is also used.

G-7-6: Stream and File Handling

The operations implemented are opening, closing, querying status, flushing, error handling, setting.

The predicates in the 'see' and 'tell' families are supplied for DEC-10 Prolog compatibility. They take either file specifications or stream objects as arguments (see section L-1) and they specify an alternative, less powerful, mechanism for dealing with files and streams than the similar predicates (open/[3,4], etc.) which take stream objects (see Figure G-7-1).

Figure G-7-1: Categorization of Stream Handling Predicates

G-7-6-1: Stream Objects

Each input and output stream is represented by a unique Prolog term, a stream_object. In general, this term is of the form


        '$stream'(X).

where X is an integer. In addition, the following terms are used to identify the standard I/O streams:


        user_input
        user_output
        user_error

  

Stream objects are created by the predicate open/[3,4] and passed as arguments to those predicates which need them. Representation for stream objects to be used in C code is different. Use stream_code/2 to convert from one to the other when appropriate.

G-7-6-2: Exceptions related to Streams

All predicates which take a stream argument will raise the following exceptions:

The reference page for each stream predicate will simply refer to these as "Stream errors" and will go on to detail other exceptions that may be raised for a particular predicate.

G-7-6-3: Suppressing Error Messages

nofileerrors/0 resets the 'fileerrors' flag, so that the built-in predicates which open files simply fail, instead of raising an exception if the specified file cannot be opened.

To cancel the effect of fileerrors/0, call nofileerrors/0. It sets the 'fileerrors' flag to its default state in which an error message is produced by see/1, tell/1, and open/3 if the specified file cannot be opened. The error message is followed by an abort/0; that is, execution of the program is abandoned and the system returns to top level.

The 'fileerrors' flag is only enabled or disabled by an explicit call to fileerrors/0 or nofileerrors/0, or via prolog_flag/[2,3] which can also be used to obtain the current value of the fileerrors flag. See section G-10, for more information on the fileerrors flag.

G-7-6-4: Opening a Stream

Before I/O operations can take place on a stream, the stream must be opened, and it must be set to be current input or current output. As illustrated in Figure G-7-1, the operations of opening and setting are separate with respect to the stream predicates, and combined in the File Specification Predicates.

Opening a stream and making it current are combined in see and tell:

It is important to remember to close streams when you have finished with them. Use seen/0 or close/1 for input files, and told/0 or close/1 for output files.

G-7-6-5: Finding the Current Input Stream

G-7-6-6: Finding the current output stream

G-7-6-7: Backtracking through Open Streams

current_stream(*File, *Mode, *Stream) succeeds if Stream is a stream which is currently open on file File in mode Mode, where Mode is either 'read', 'write', or 'append'. None of the arguments need be initially instantiated. This predicate is non-determinate and can be used to backtrack through all open streams. It fails when there are no (further) matching open streams.

current_stream/3 ignores the three special streams for the standard input, output, and error channels.

G-7-6-8: Closing a Stream

G-7-6-9: Flushing Output

Output to a stream is not necessarily sent immediately; it is buffered. The predicate flush_output/1 flushes the output buffer for the specified stream and thus ensures that everything that has been written to the stream is actually sent at that point.

G-7-7: Reading the State of Opened Streams

Character count, line count and line position for a specified stream are obtained as follows:

G-7-7-1: Stream Position Information for Terminal I/O

Input from Prolog streams which have opened the user's terminal for reading is echoed back as output to the same terminal. This is interleaved with output from other Prolog streams which have opened the user's terminal for writing. Therefore, all streams connected to the user's terminal share the same set of position counts and thus return the same values for each of the predicates character_count/2, line_count/2, and line_position/2. The following example assumes that 'user_input', 'user_output', and 'user_error' are all connected to the user's terminal (which may not always be true if I/O is being redirected),


        | ?- line_count(user, X1),
             line_count(user_input, X2),
             line_count(user_output, X3),
             line_count(user_error, X4).

        X1 = X2 = X3 = X4 = 36 ;

        no
        | ?- line_position(user, X1),
             line_position(user_input, X2),
             line_position(user_output, X3),
             line_position(user_error, X4).

        X1 = X2 = X3 = X4 = 0 ;

        no
        | ?- character_count(user, X1),
             character_count(user_input, X2),
             character_count(user_output, X3),
             character_count(user_error, X4).

        X1 = X2 = X3 = X4 = 1304 ;

        no

G-7-8: Random Access to Files

There are two methods of finding and setting the stream position, stream positioning and seeking. The current position of the read/write pointer in a specified stream can be obtained by using stream_position/2. It may be changed by using stream_position/3. Alternatively, seek/4 may be used.

Seeking is more general, and stream positioning is more portable. The differences between them are:

G-7-9: Summary of Predicates and Functions

Reference pages for the following provide further detail on the material in this chapter.

at_end_of_file/[0,1] read_term/[2,3] at_end_of_line/[0,1] see/1 character_count/2 seeing/1 close/1 seek/4 current_input/1 seen/0 current_output/1 set_input/1 current_stream/3 set_output/1 display/1 skip/[1,2] fileerrors/0 skip_line/[0,1] flush_output/1 stream_position/[2,3] format/[2,3] tab/[1,2] get0/[1,2] tell/1 get/[1,2] telling/1 line_count/2 told/0 line_position/2 ttyflush/0 nl/[0,1] ttyget0/1 nofileerrors/0 ttyget/1 open/[3,4] ttynl/0 open_null_stream/1 ttyput/1 peek_char/[1,2] ttyskip/1 portray/1 ttytab/1 portray_clause/1 write/[1,2] print/[1,2] write_canonical/[1,2] prompt/[2,3] writeq/[1,2] put/[1,2] write_term/[2,3] read/[1,2]

Also, see Chapter I-5.

G-7-10: Library Support

add_portray printchars plint


Copyright (C) 1998 SICS
contact: product support sales information