Bug hunting toolbox

There is a 32000 character limit for post that is inherited from the DB size of a field. It can be changed but we don’t. So another reply is added to continue the collection of knowledge.


From Jan W. (ref)

Without really answering your question, did you discover the SSU rules (Head => Body) and det/1? Since I use those, debugging time has been reduced a lot. Other recent goodies are trap/1 and gtrap/1 to quickly get the debugger at an exception. And of course, there is check/0 to do some static analysis, be it a lot less than mercury. And, last but not least the new “sweeprolog” mode for GNU emacs or the built-in Emacs clone save you a lot of work.


For creating a test case that mocks an external resourceby Jan W. (ref)

There is nothing out of the box. There are lots of options though. For example, implement a mock version of the library that calls the external service and load it instead of the real thing by changing the (library) search path. You can also use wrap_predicate/4 to create a wrapper around any predicate. That is intended to call the original, but of course you don’t need to. You can even abolish/1 the old predicate and assert a new definition.

None of that is portable. Wrapping predicates is really SWI-Prolog specific. There is no portability in search path handling (but many systems have it) and ISO turned abolish/1 into something useless because you can only use it on dynamic code where, in addition to retractall/1, it removes the predicate properties (dynamic, etc.) SWI-Prolog kept the pre-ISO semantics where abolish/1 applies to any predicate.

Than you need an alternative implementation for the external server. I don’t know how much you can generalize that. I guess it can be anything.


Per Jan W. (ref)

Note that for indexing, atoms are faster than strings as atoms just look at the handle and strings actually need to access the text.


Per Jan W. (ref)

library(yall) is broken in the sense that the compiled behaviour differs from interpreted behaviour for variables shared with the rest of the clause. If you load the code without explicitly loading the library it is used interpreted. If you then use it and reload, it is compiled. So, always make sure library(yall) is loaded and make sure all meta-predicates through with it is called are loaded (or built-in). You can enable

 :- set_prolog_flag(warn_autoload, true).

to get a warning about libraries that use goal/term expansion and are not loaded before the code is called. The default is still false. Might change to true shortly. It still occasionally gives a few somewhat misleading warnings :frowning:

If you use library(yall), you must really understand it :frowning: I recommend using listing/1 on the predicates in which you use it to make sure it is compiled. Interpreted yall is semantically different and very slow.


Handling Unicode in SWI-Prolog

When working with Unicode characters in SWI-Prolog where comparisons involve both internal code and external files, proper encoding configuration is essential.

Common Issue

Unicode comparison failures often occur when SWI-Prolog code uses one encoding internally while external files use another. This typically happens when:

  1. Code is initially loaded with default text encoding
  2. A directive in the code later changes the encoding
  3. Files are then loaded with the new encoding
  4. Comparisons fail due to encoding mismatch

Typical Failure Example

Consider this sequence of operations:

% Step 1: Load module with default 'text' encoding
?- [my_unicode_module].

% Inside my_unicode_module.pl:
:- set_prolog_flag(encoding, utf8).  % This directive comes too late!

process_file(Filename) :-
    open(Filename, read, Stream, [encoding(utf8)]),
    read_string(Stream, _, Content),
    close(Stream),
    % This comparison will fail:
    compare_with_unicode("北京", Content).

Why This Fails

  1. The module my_unicode_module.pl is loaded with the default text encoding
  2. All Unicode literals in the module (like "北京") are encoded using this default encoding
  3. The directive :- set_prolog_flag(encoding, utf8) only affects operations after the module is loaded
  4. When process_file/1 reads the external file with explicit utf8 encoding
  5. The comparison fails because "北京" in the code and the same characters from the file have different internal representations

Solution

To ensure consistent Unicode handling:

  1. Set the encoding flag before loading any modules:
    ?- set_prolog_flag(encoding, utf8).
    ?- [my_unicode_module].
    

This approach ensures both your Prolog code and external files use the same Unicode encoding (utf8), making character comparisons reliable, especially when using DCG for parsing Unicode input files.