Best practices for printing

This is from a reply by Jan W.

Best practice seems to be

  • Use format/3 to emit non-term output.
  • When writing a library, use the print_message/2 indirection for talking to the user.
  • Use writeq/1 or write_canonical/1 to write terms that need to be read by Prolog.
  • Use portray_clause/1 for listing clauses. This predicate must ensure that reading returns the same clause given the same operator declarations.
  • Use print/1 only for debug/3 and other interactive use of your program.
  • Be careful with portray/1. Only use it for very specific terms for libraries or better, include a dedicated portray library for a specific library. rdf_portray.pl is such as beast for dealing with RDF.
  • write/1 should never have been added to Prolog.
8 Likes

Also worth mentioning IMO:

  • write_term/2 if you want to print a term and need finer control over how quoting, operators, variables, etc. are handled
  • print_term/2 from library(pprint) pretty-prints terms with more human-readable formatting, and has some extra options to control this
  • write_canonical/1 on SWI prints lists using list syntax and not as compound terms, as this would expose SWI’s '[|]' list term functor. If this is a problem and you really need it printed in plain compound term syntax, use write_term/2 with the option dotlists(true) or no_lists(true) (depending on whether you want lists to be printed using the traditional '.' functor or SWI’s '[|]' functor). Note that these options are SWI-specific - on other Prolog systems, the ignore_ops option controls whether list syntax is used.
5 Likes

Another way of getting finer control is to “print” to a string and then modify it, by using with_output_to/2 and the current_output stream alias. For example:

print_term_cleaned(Term, Options) :-
    with_output_to(string(TermStr0),
        print_term(Term, [tab_width(0),output(current_output)|Options])),
    re_replace(" +\n"/g, "\n", TermStr0, TermStr1),    % remove trailing whitespace
    re_replace("\t"/g, "        ", TermStr1, TermStr). % replace tabs by blanks
    write(TermStr).

For SWISH consider

From this reply by Jan W.

… one should be aware that calling write/1 twice on the same variable may not print the same value. This is because the print output are stack offsets and GC changes these. There is not a good way around that. For this type of exploration you may consider

?- set_prolog_flag(gc, false).
to disable garbage collection. Be careful, you easily run out of memory.

As is, variables appearing in a term that is printed as a whole are consistent, unless portray hooks are used. Printing a term reliably is pretty hard. The toplevel uses copy_term/3 to move the constraints out, if the term is cyclic it factorizes the cycles. Next it uses numbervars/4 with the singletons(true) argument and finally prints using portray and numbervars options.

1 Like