4.17 Input and output
AllApplicationManualNameSummaryHelp

  • Documentation
    • Reference manual
      • Built-in Predicates
        • Input and output
          • Predefined stream aliases
          • ISO Input and Output Streams
          • Edinburgh-style I/O
            • see/1
            • tell/1
            • append/1
            • seeing/1
            • telling/1
            • seen/0
            • told/0
          • Switching between Edinburgh and ISO I/O
          • Adding IRI schemas
          • Write onto atoms, code-lists, etc.
          • Fast binary term I/O
    • Packages

4.17.3 Edinburgh-style I/O

The package for implicit input and output destinations is (almost) compatible with Edinburgh DEC-10 and C-Prolog. The reading and writing predicates refer to, resp., the current input and output streams. Initially these streams are connected to the terminal. The current output stream is changed using tell/1 or append/1. The current input stream is changed using see/1. The stream's current value can be obtained using telling/1 for output and seeing/1 for input.

Source and destination are either a file, user, or a term‘pipe(Command)'. The reserved stream name user refers to the terminal.101The ISO I/O layer uses user_input, user_output and user_error. In the predicate descriptions below we will call the source/destination argument‘SrcDest’. Below are some examples of source/destination specifications.

?- see(data). % Start reading from file‘data'.
?- tell(user). % Start writing to the terminal.
?- tell(pipe(lpr)). % Start writing to the printer.

Another example of using the pipe/1 construct is shown below.102As of version 5.3.15, the pipe construct is supported in the MS-Windows version, both for swipl.exe and swipl-win.exe. The implementation uses code from the LUA programming language (http://www.lua.org). Note that the pipe/1 construct is not part of Prolog's standard I/O repertoire.

getwd(Wd) :-
        seeing(Old), see(pipe(pwd)),
        collect_wd(String),
        seen, see(Old),
        atom_codes(Wd, String).

collect_wd([C|R]) :-
        get0(C), C \== -1, !,
        collect_wd(R).
collect_wd([]).

The effect of tell/1 is not undone on backtracking, and since the stream handle is not specified explicitly in further I/O operations when using Edinburgh-style I/O, you may write to unintended streams more easily than when using ISO compliant I/O. For example, the following query writes both "a" and "b" into the file‘out' :

?- (tell(out), write(a), false ; write(b)), told.

Compatibility notes

Unlike Edinburgh Prolog systems, telling/1 and seeing/1 do not return the filename of the current input/output but rather the stream identifier, to ensure the design pattern below works under all circumstances:103Filenames can be ambiguous and SWI-Prolog streams can refer to much more than just files.

        ...,
        telling(Old), tell(x),
        ...,
        told, tell(Old),
        ...,

The predicates tell/1 and see/1 first check for user, the pipe(command) and a stream handle. Otherwise, if the argument is an atom it is first compared to open streams associated to a file with exactly the same name. If such a stream exists, created using tell/1 or see/1, output (input) is switched to the open stream. Otherwise a file with the specified name is opened.

The behaviour is compatible with Edinburgh Prolog. This is not without problems. Changing directory, non-file streams, and multiple names referring to the same file easily lead to unexpected behaviour. New code, especially when managing multiple I/O channels, should consider using the ISO I/O predicates defined in section 4.17.2.

see(+SrcDest)
Open SrcDest for reading and make it the current input (see set_input/1). If SrcDest is a stream handle, just make this stream the current input. See the introduction of section 4.17.3 for details.
tell(+SrcDest)
Open SrcDest for writing and make it the current output (see set_output/1). If SrcDest is a stream handle, just make this stream the current output. See the introduction of section 4.17.3 for details.
append(+File)
Similar to tell/1, but positions the file pointer at the end of File rather than truncating an existing file. The pipe construct is not accepted by this predicate.
seeing(?SrcDest)
Same as current_input/1, except that user is returned if the current input is the stream user_input to improve compatibility with traditional Edinburgh I/O. See the introduction of section 4.17.3 for details.
telling(?SrcDest)
Same as current_output/1, except that user is returned if the current output is the stream user_output to improve compatibility with traditional Edinburgh I/O. See the introduction of section 4.17.3 for details.
seen
Close the current input stream. The new input stream becomes user_input.
told
Close the current output stream. The new output stream becomes user_output.