8.1.3 Input and Output of Terms

Most of the following predicates come in two versions, with or without a stream argument. Predicates without a stream argument operate on the current input or output stream, depending on context. Predicates with a stream argument can take stream reference or an alias in this argument position, the alias being replaced by the stream it was associated with.

Some of these predicates support a notation for terms containing multiple occurrences of the same subterm (cycles and DAGs). The notation is @(Template,Substitution) where Substitution is a list of Var=Term pairs where the Var occurs in Template or in one of the Terms. This notation stands for the instance of Template obtained by binding each Var to its corresponding Term. The purpose of this notation is to provide a finite printed representation of cyclic terms. This notation is not used by default, and @/2 has no special meaning except in this context.

read(?Term) ISO
read(+Stream,?Term) ISO
The next term, delimited by a full-stop (i.e. a `.', possibly followed by layout text), is read from Stream and is unified with Term. The syntax of the term must agree with current operator declarations. If a call read(Stream,Term) causes the end of Stream to be reached, Term is unified with the term end_of_file. Further calls to read/2 for the same stream will then raise an exception, unless the stream is connected to the terminal. The characters read are subject to character-conversion, see below.
read_term(?Term,+Options) ISO
read_term(+Stream,?Term,+Options) ISO
Same as read/[1,2] with a list of options to provide extra control or information about the term. Options is a list of zero or more of:
syntax_errors(+Val)
Controls what action to take on syntax errors. Val must be one of the values allowed for the syntax_errors Prolog flag. The default is set by that flag.
variables(?Vars)
Vars is bound to the list of variables in the term input, in left-to-right traversal order.
variable_names(?Names)
Names is bound to a list of Name=Var pairs, where each Name is an atom indicating the name of a non-anonymous variable in the term, and Var is the corresponding variable.
singletons(?Names)
Names is bound to a list of Name=Var pairs, one for each variable appearing only once in the term and whose name does not begin with `_'.
cycles(+Boolean)
Boolean must be true or false. If selected, any occurrences of @/2 in the term read in are replaced by the potentially cyclic terms they denote as described above. Otherwise (the default), Term is just unified with the term read in.
layout(?Layout)
Layout is bound to a layout term corresponding to Term. The layout Y of a term X is one of:
  • If X is a variable or atomic term, Y is the number of the line where X occurs.
  • If X is a compound term, Y is a list whose head is the number of the line where the first token of X occurs, and whose remaining elements are the layouts of the arguments of X.
  • [], if no line number information is available for X.

consume_layout(+Boolean)
Boolean must be true or false. If this option is true, read_term/[2,3] will consume the layout-text-item that follows the terminating `.' (this layout-text-item can either be a layout-char or a comment starting with a `%'). If the option is false, the layout-text-item will remain in the input stream, so that subsequent character input predicates will see it. The default of the consume_layout option is true in sicstus execution mode, and it is false in iso execution mode.
          | ?- read_term(T, [layout(L), variable_names(Va), singletons(S)]).
          |: [
               foo(X),
               X = Y
               ].
          
          L = [35,[36,36],[36,[37,37,37],38]],
          S = ['Y'=_A],
          T = [foo(_B),_B=_A],
          Va = ['X'=_B,'Y'=_A]
          
          | ?- read_term(T, [consume_layout(false)]), get_code(C).
          |: 1.
          
          C = 10,
          T = 1
          
          | ?- read_term(T, [consume_layout(true)]), get_code(C).
          |: 1.
          |: a
          
          C = 97,
          T = 1
     

char_conversion(+InChar, +OutChar) ISO
InChar and OutChar should be one-char atoms. If they are not the same, then the mapping of InChar to OutChar is added to the character-conversion mapping. This means that in all subsequent term and program input operations any unquoted occurrence of InChar will be replaced by OutChar. The rationale for providing this facility is that in some extended character sets (such as Japanese JIS character sets) the same character can appear several times and thus have several codes, which the users normally expect to be equivalent. It is advisable to always quote the arguments of char_conversion/2.

If InChar and OutChar are the same, the effect of char_conversion/2 is to remove any mapping of InChar from the character-conversion mapping.

current_char_conversion(?InChar, ?OutChar) ISO
The character of one-char atom InChar is mapped to that of the one-char atom OutChar in the current character-conversion mapping. Enumerates all such pairs on backtracking.
write(?Term) ISO
write(+Stream,?Term) ISO
The term Term is written onto Stream according to current operator declarations. Same as write_term([Stream,] Term, [numbervars(true)]).
display(?Term)
The term Term is displayed onto the standard output stream (which is not necessarily the current output stream) in standard parenthesized prefix notation. Same as write_term(user, Term, [ignore_ops(true)]).
write_canonical(?Term) ISO
write_canonical(+Stream,?Term) ISO
Similar to write(Stream,Term). The term will be written according to the standard syntax. The output from write_canonical/2 can be parsed by read/2 even if the term contains special characters or if operator declarations have changed. Same as write_term([Stream,] Term, [quoted(true),ignore_ops(true)]).
writeq(?Term) ISO
writeq(+Stream,?Term) ISO
Similar to write(Stream,Term), but the names of atoms and functors are quoted where necessary to make the result acceptable as input to read/2, provided the same operator declarations are in effect. Same as write_term([Stream,] Term, [quoted(true),numbervars(true)]).
print(?Term) hookable
print(+Stream,?Term) hookable
Prints Term onto Stream. This predicate provides a handle for user defined pretty printing:

In particular, the debugging package prints the goals in the tracing messages, and the top-level prints the final values of variables. Thus you can vary the forms of these messages if you wish.

Note that on lists ([_|_]), print/2 will first give the whole list to user:portray/1, but if this fails it will only give each of the (top-level) elements to user:portray/1. That is, user:portray/1 will not be called on all the tails of the list.

Same as write_term([Stream,] Term, [portrayed(true),numbervars(true)]).

portray(+Term) hook
user:portray(+Term)
This should either print the Term and succeed, or do nothing and fail. In the latter case, the default printer (write/1) will print the Term.
portray_clause(?Clause)
portray_clause(+Stream,?Clause)
Writes the clause Clause onto Stream exactly as listing/[0,1] would have written it. Same as write_term([Stream,] Term, [quoted(true),numbervars(true),indented(true)]) followed by a period and a newline and binding variables to terms of the form '$VAR'(N) yielding friendlier variable names.
write_term(+Term,+Options) ISO
write_term(+Stream,+Term,+Options) ISO
Same as write/[1,2] etc. with a list of options to provide extra control. This predicate in fact subsumes the above output predicates except portray_clause/[1,2], which additionally prints a period and a newline, and removes module prefixes that are redundant wrt. the current type-in module. Options is a list of zero or more of the following, where Boolean must be true or false (false is the default).
quoted(+Boolean)
If selected, functors are quoted where necessary to make the result acceptable as input to read/1. write_canonical/1, writeq/1, and portray_clause/1 select this.
ignore_ops(+Boolean)
If selected, Term is written in standard parenthesized notation instead of using operators. write_canonical/1 and display/1 select this.
portrayed(+Boolean)
If selected, user:portray/1 is called for each subterm. print/1 selects this.
numbervars(+Boolean)
If selected, terms of the form '$VAR'(N) where N is an integer >= 0, an atom, or a code-list, are treated specially (see numbervars/3). print/1, write/1, writeq/1, and portray_clause/1 select this.
cycles(+Boolean)
If selected, the potentially cyclic term is printed in finite @/2 notation, as discussed above.
indented(+Boolean)
If selected, the term is printed with the same indentation as is used by portray_clause/1 and listing/[0,1].
max_depth(+Depth)
Depth limit on printing. Depth is an integer. 0 (the default) means no limit.
character_escapes(+Boolean)
If selected, quoted atoms containing special characters will be printed using escape sequences (see Escape Sequences). The default value depends on the character_escapes Prolog flag.
float_format(+Spec)
How to print floats. Spec should be an atom of the form `~NC', like one of the format/[2,3] character sequences for printing floats. The default is `~H'.
priority(+Prio)
The term is printed as if in the context of an associative operator of precedence Prio, where Prio is an integer. The default is 1200. See Operators.

format(+Format,:Arguments)
format(+Stream,+Format,:Arguments)
Prints Arguments onto Stream according to format Format. Format is an atom or a code-list of formatting characters. If Format is an atom, it will be converted to a code-list. Thus:
          | ?- format("Hello world!\n", []).
     

has the same effect as

          | ?- format('Hello world!\n', []).
     

no matter which value the double_quotes Prolog flag has. format/[2,3] is the Prolog equivalent to the C stdio function printf().

Arguments is a list of items to be printed. If there are no items then an empty list should be supplied.

The default action on a format character is to print it. The character `~' introduces a control sequence. To print a `~' repeat it:

          | ?- format('Hello ~~world!\n', []).
          Hello ~world!
     

Unless character escapes have been switched off, the escape sequence (see Escape Sequences) `\c' (c for continue) is useful when formatting a string for readability. It causes all characters up to, but not including, the next non-layout character to be ignored.

          | ?- format('Hello \c
                       world!\n', []).
          Hello world!
     

The general format of a control sequence is `~NC'. The character C determines the type of the control sequence. N is an optional numeric argument. An alternative form of N is `*'. `*' implies that the next argument in Arguments should be used as a numeric argument in the control sequence. Example:

          | ?- format('Hello~4cworld!\n', [0'x]).
          Helloxxxxworld!
          
          | ?- format('Hello~*cworld!\n', [4,0'x]).
          Helloxxxxworld!
     

The following control sequences are available.

`~a'
The argument is an atom. The atom is printed without quoting.
`~Nc'
(Print character.) The argument is a number that will be interpreted as a character code. N defaults to one and is interpreted as the number of times to print the character.
`~Ne'
`~NE'
(Print float in exponential notation.) The argument is a float, which will be printed in exponential notation with one digit before the decimal point and N digits after it. If N is zero, one digit appears after the decimal point. A sign and at least two digits appear in the exponent, which is introduced by the letter used in the control sequence. N defaults to 6. Examples:
               | ?- Pi=3.14159265, format('~e ~2E ~0E\n', [Pi,Pi,Pi]).
               3.141593e+00 3.14E+00 3.0E+00
          

`~Nf'
`~NF'
(Print float in fixed-point notation.) The argument is a float, which will be printed in fixed-point notation with N digits after the decimal point. N may be zero, in which case a zero appears after the decimal point. At least one digit appears before it and at least one after it. N defaults to 6. Examples:
               | ?- Pi=3.14159265, format('~f, ~2F, ~0F\n', [Pi,Pi,Pi]).
               3.141593, 3.14, 3.0
          

`~Ng'
`~NG'
(Print float in generic notation.) The argument is a float, which will be printed in `f' or `e' (or `E' if `G' is used) notation with N significant digits. If N is zero, one significant digit is printed. `E' notation is used if the exponent from its conversion is less than -4 or greater than or equal to N, otherwise `f' notation. Trailing zeroes are removed from the fractional part of the result. A decimal point and at least one digit after it always appear. N defaults to 6. Examples:
               | ?- format('~g ~2G ~0G\n', [1.23456789e+10, 3.14159265, 0.0123]).
               1.23457e+10 3.1 0.01
          

`~Nh'
`~NH'
(Print float precisely.) The argument is a float, which will be printed in `f' or `e' (or `E' if `H' is used) notation with d significant digits, where d is the smallest number of digits that will yield the same float when read in. `E' notation is used if N<0 or if the exponent is less than -N-1 or greater than or equal to N+d, otherwise `f' notation. N defaults to 3. Examples:
               | ?- F = 123000.0, G = 0.000123,
                    format('~h ~h ~2h ~2H ~-1H\n', [F,G,F,G,3.14]).
               123000.0 0.000123 1.23e+05 1.23E-04 3.14E+00
          

The intuition is that for numbers like 123000000.0, at most N consecutive zeroes before the decimal point are allowed in `f' notation. Similarly for numbers like 0.000000123.

`E' notation is forced by using `~-1H'. `F' is forced by using `~999H'.

`~Nd'
(Print decimal.) The argument is an integer. N is interpreted as the number of digits after the decimal point. If N is 0 or missing, no decimal point will be printed. Example:
               | ?- format('Hello ~1d world!\n', [42]).
               Hello 4.2 world!
               
               | ?- format('Hello ~d world!\n', [42]).
               Hello 42 world!
          

`~ND'
(Print decimal.) The argument is an integer. Identical to `~Nd' except that `,' will separate groups of three digits to the left of the decimal point. Example:
               | ?- format('Hello ~1D world!\n', [12345]).
               Hello 1,234.5 world!
          

`~Nr'
(Print radix.) The argument is an integer. N is interpreted as a radix, 2 \leq N \leq 36. If N is missing the radix defaults to 8. The letters `a-z' will denote digits larger than 9. Example:
               | ?- format('Hello ~2r world!\n', [15]).
               Hello 1111 world!
               
               | ?- format('Hello ~16r world!\n', [15]).
               Hello f world!
          

`~NR'
(Print radix.) The argument is an integer. Identical to `~Nr' except that the letters `A-Z' will denote digits larger than 9. Example:
               | ?- format('Hello ~16R world!\n', [15]).
               Hello F world!
          

`~Ns'
(Print string.) The argument is a code-list. Exactly N characters will be printed. N defaults to the length of the string. Example:
               | ?- format('Hello ~4s ~4s!\n', ["new","world"]).
               Hello new  worl!
               
               | ?- format('Hello ~s world!\n', ["new"]).
               Hello new world!
          

`~i'
(Ignore.) The argument, which may be of any type, is ignored. Example:
               | ?- format('Hello ~i~s world!\n', ["old","new"]).
               Hello new world!
          

`~k'
(Print canonical.) The argument may be of any type. The argument will be passed to write_canonical/1 (see Term I/O). Example:
               | ?- format('Hello ~k world!\n', [[a,b,c]]).
               Hello .(a,.(b,.(c,[]))) world!
          

`~p'
(Print.) The argument may be of any type. The argument will be passed to print/1 (see Term I/O). Example:
               | ?- assert((portray([X|Y]) :- print(cons(X,Y)))).
               | ?- format('Hello ~p world!\n', [[a,b,c]]).
               Hello cons(a,cons(b,cons(c,[]))) world!
          

`~q'
(Print quoted.) The argument may be of any type. The argument will be passed to writeq/1 (see Term I/O). Example:
               | ?- format('Hello ~q world!\n', [['A','B']]).
               Hello ['A','B'] world!
          

`~w'
(Write.) The argument may be of any type. The argument will be passed to write/1 (see Term I/O). Example:
               | ?- format('Hello ~w world!\n', [['A','B']]).
               Hello [A,B] world!
          

`~@'
(Call.) The argument is a goal, which will be called and expected to print on the current output stream. If the goal performs other side-effects or does not succeed determinately, the behavior is undefined. Example:
               | ?- format('Hello ~@ world!\n', [write(new)]).
               Hello new world!
          

`~~'
(Print tilde.) Takes no argument. Prints `~'. Example:
               | ?- format('Hello ~~ world!\n', []).
               Hello ~ world!
          

`~Nn'
(Print newline.) Takes no argument. Prints N newlines. N defaults to 1. Example:
               | ?- format('Hello ~n world!\n', []).
               Hello
                world!
          

`~N'
(Print Newline.) Prints a newline if not at the beginning of a line.

The following control sequences set column boundaries and specify padding. A column is defined as the available space between two consecutive column boundaries on the same line. A boundary is initially assumed at line position 0. The specifications only apply to the line currently being written.

When a column boundary is set (`~|' or `~+') and there are fewer characters written in the column than its specified width, the remaining space is divided equally amongst the pad sequences (`~t') in the column. If there are no pad sequences, the column is space padded at the end.

If `~|' or `~+' specifies a position preceding the current position, the boundary is set at the current position.

`~N|'
Set a column boundary at line position N. N defaults to the current position.
`~N+'
Set a column boundary at N positions past the previous column boundary. N defaults to 8.
`~Nt'
Specify padding in a column. N is the fill character code. N may also be specified as `C where C is the fill character. The default fill character is <SPC>. Any (`~t') after the last column boundary on a line is ignored.
Example:
          | ?-    format('~`*t NICE TABLE ~`*t~61|~n', []),
                  format('*~t*~61|~n', []),
                  format('*~t~a~20|~t~a~t~20+~a~t~20+~t*~61|~n',
                         ['Right aligned','Centered','Left aligned']),
                  format('*~t~d~20|~t~d~t~20+~d~t~20+~t*~61|~n',
                         [123,45,678]),
                  format('*~t~d~20|~t~d~t~20+~d~t~20+~t*~61|~n',
                         [1,2345,6789]),
                  format('~`*t~61|~n', []).
     
          ************************ NICE TABLE *************************
          *                                                           *
          *      Right aligned      Centered      Left aligned        *
          *                123         45         678                 *
          *                  1        2345        6789                *
          *************************************************************