Search code examples
prologswi-prolog

How to get SWI-Prolog to always print strings with quotes, in interactive mode


When using SWI-prolog, it will print output that doesn't need to be quoted (output that doesn't contain special characters), without quotes. As an example:

?- p('this_is_a_string').
true.

?- p(X).
X = this_is_a_string.

I would like Prolog to always output with quotes. It is okay if my output ends up quoting stuff like functor names, which were not originally quoted when input. How can I achieve this?


Solution

  • To change the default behaviour of SWI-Prolog's top-level output, you want to look towards setting a flag. If you query the appropriate flag, you should find this is your default output:

    ?- current_prolog_flag(print_write_options, Options).
    Options = [portray('true'), quoted('true'), numbervars('true')]. 
    

    In this particular case, the needed flag is already set: we have portray('true') in our Options.

    portray/1 is a dynamic predicate that you can assert. It's called with a ground term when it is being printed, if it succeeds then it's assumed the the term has been printed.

    So in your case you can assert the following:

    portray(Term) :- atom(Term), format("'~s'", Term).
    

    Now you'll get the desired behaviour:

    ?- p(this_is_an_atom).
    true.
    
    ?- p(X).
    X = 'this_is_an_atom'.
    

    You could add this to your .swiplrc file if it's something you want all the time. Note, this will have no effect on write/1 and similar predicates, you'll need to use this instead:

    ?- write_term(foo, [portray(true)]).
    'foo'.
    

    To add the additional requirement of escaping characters in the the atom, you'll either need to implement your own DCG to the ISO standard for escaping characters, or abuse the built-in one. To do this you can write out to an atom and see if you need to add your single-quotes, or if they would already be there. The case of X = (\). is most easily handled in its own clause, you can then choose if you wish to print '\\' or (\).

    portray(\) :-
        format("'\\\\'"), !.
    portray(Term) :-
        atom(Term), \+ Term = (\),
        ( with_output_to(chars(['\''|_]),
            write_term(Term, [quoted(true), character_escapes(true), portrayed(false)]))
        -> format("~q", Term)
        ; format("'~s'", Term)
        ).