Thanks for the nice list of options. I examined by list at write_term/2. Some of the stuff is of no general interest, but some might be. Notably
module(+Module) Should possibly/probably be handled differently, but this controls the set of operators as well as the SWI-Prolog module-specific Prolog flags that control read/write (e.g., the ISO flags that control how double and backquoted strings are read).
partial(+Bool) If true, the token separation logic associated with the stream is not reset. That implies that a subsequent write_term/2 call will insert a space if its output will glue at the token level with the output of the last write_term/2 to this stream. This is a generalization of the full_stop option. It extends the embedding provided by priority.
portray_goal(:Goal) Sets the portrayed option, but calling the given predicate. I found this very useful in controlling the output of term writing. It can even deal with printing numbers
quote_non_ascii(+Bool) This deals with different Prolog systems handling Unicode differently. AFAIK, SICStus only deals with Unicode in quoted atoms/strings, whereas SWI-Prolog assigns Prolog character classes to all Unicode characters and it will thus write atoms holding lowercase letters in any script without quotes. Using this option, it will quote such atoms.
I suppose this is because of shortcomings of the Quintus module system? ECLiPSe handles this with the normal context-module mechanism. Can’t write_term be made a meta-predicate? And how is the problem (of looking up local operators and syntax options) solved in other builtins like write/writeq/print/1,2, where you don’t have options?
Can you make this more precise? I checked my write-implementation, and there I need a total of 8 context-flags (in addition to priority) to get all spacing/quoting/parenthesizing of subterms right. These essentially encode in what context a subterm occurs within its printed parent term. I suppose your single boolean flag must correspond to some conservative worst-case, such as “following a prefix operator”?
This looks attractive at first sight. On the other hand, for printing atomic subterms, it is heavy: you call the goal for every subterm, have to type-test for filtering and possibly fail. For implementing some kind of term pretty printing, with write_term calling the portray-goal on every subterm, and the portray-goal calling write_term back, I suspect that the threading-through and adjustment of the write_options quickly gets as complicated as replicating the whole term-write algorithm in Prolog…
This could be covered by the atom(quote(+When)) option I proposed.
No. If you want to support this in write/1, there would be a problem with Quintus, but SWI-Prolog’s module system can deal with that
It is more a consideration that came from portability concerns when I introduced module-local operators. I was too afraid that using the normal context mechanism for read and write would break too much. As it is rather rare that you want to read or write using module specific operators I added the module(+Module) option to read_term/2,3 and write_term/2,3. Maybe I was overly concerned?
A stream maintains the last character written and some flags. Normally a call to write/1, etc. reset this at start. If partial(true) is given, this logic is not reset and needSpace(int c, IOSTREAM*s) tells us whether or not a space is required to make c not glue to the last emitted token.
It is seems I only need three flags and the last character of the previous token to decide on the need for a space. I think one is even due to a SWI-Prolog “feature” to read e.g. - 2 as -(2), i.e., it does not allow for white space between the sign and a number.
But, I do not know whether this is enough state to make the partial write always correct. But then, we all have priority and that does certainly not cope with everything. The option partial(true) does not prevent us to save more information.
This is a great discussion. However, I’m wondering whether, if we end up having a lot of write_term options it would be good to delegate some of these to an “advanced” group. Module-specific write_term flags are important for people who write libraries, but less so for general users, I think.
Definitely. I have committed an updated draft – it would be great if tomorrow we could go through and at classify them into something like accepted/recommended/deluxe/rejected.