Using a Prolog Format Predicate to Print to a File

Can I use the format prolog predicate to print to a file?

I have a data table that I print to stdout using a format predicate, i.e.

 print_table :- print_table_header, forall(range(1.0,10.0,0.1,N), print_row(N,L)). %% print_row(L) :- take a list of the form, [a,b,c,d,e] and %% print it to screen as a single row of tab separated float values (1DP) print_row(N,L) :- build_row(N,L), format('~t~1f~10+ ~t~1f~10+ ~t~1f~10+ ~t~1f~10+ ~t~1f~10+ ~n', L). print_table_header :- format('~t~w~10+ ~t~w~10+ ~t~w~10+ ~t~w~10+ ~t~w~10+ ~n', ['N','N2','N3','N4','N5']). 

it would be nice to somehow reuse the code to print the same file.

+4
source share
3 answers

You can!

Consider the following SICStus Prolog documentation excerpt for format/[2,3] :

11.3.85 format / [2,3]

Summary

format (+ Control, + Arguments)

format (+ Stream, + Control, + Arguments)

Interprets the arguments according to the Control string and prints the result to Stream.

format/[2,3] predicates are widely supported in Prolog implementations.

However, at the moment, these predicates are not part of the ISO Prolog.

+3
source

I would write the output "routines" with an additional parameter, Stream , and then pass the user during testing or printing to the screen. See the predicates ISO open / 3, close / 1, etc. To process a stream ...

Please note that IO is among the least "declarative" areas of the language, because for effectiveness an approach based on side effects is needed ...

SWI-Prolog has a built-in with_output_to that will allow you to reuse existing code without adding a parameter. But since you noted iso-prolog your question, you should really add the Stream parameter ...

+3
source

In addition to another good answer (+1!) I would like to present a clearer solution to such problems.

The basic idea is to make format/2 available in DCG, and then use DCG to describe the output.

It is very simple using the codes format/3 argument provided by several Prolog implementations. All you need is the following short helper definitions:

 format_(Data, Args) --> call(format_dlist(Data, Args)). format_dlist(Data, Args, Cs0, Cs) :- format(codes(Cs0,Cs), Data, Args). 

A nonterminal call//1 calls its argument with two additional arguments that allow you to access the implicit DCG arguments, and this is used to describe additional codes through format/3 .

Now we can just use nonterminal format_//2 in DCG.

For example, to describe a simple table:

 table --> row([a,b,c]), row([d,e,f]). row(Ls) --> format_("~t~w~10+~t~w~10+~t~w~10+~n", Ls). 

Usage example and result:

 ?- phrase(table, Cs), format("~s", [Cs]). abc def Cs = [32, 32, 32, 32, 32, 32, 32, 32, 32|...]. 

Note that the one last remaining format/2 used to actually input the output to the screen.

However, everything else does not contain side effects and declaratively describes the table.

An important advantage of this method is that you can easily write test cases to make sure your tables are (still) formatted correctly. It's easy to talk about lists of Prolog codes (described in DCG), but it's pretty hard to talk about things that only appear on the terminal.

+3
source

All Articles