Listing/1 does not work

I built 8.5.3 on macOS Big Sur on X86_64 and ARM64 (M1). I have a lot of problems with autoloading but I found how to disable that; I do like to understand what it means and why that is. But the most pressing problem at the moment is that listing/1 does not work anymore. I have a workspace that is maintained with assert and retract, and I cannot save work if I can not ‘tell’ a 'listing.

➜  src git:(master) ✗ swipl
Welcome to SWI-Prolog (threaded, 64 bits, version 8.5.3)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit https://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- set_prolog_flag(autoload, false).
% Disabled autoloading (loaded 25 files)
true.

?- consult('facts.qlf').
true.

?- listing.
Correct to: "prolog_listing:listing"? yes

ERROR: Unknown procedure: prolog_listing:most_general_goal/2
ERROR: In:
ERROR:   [14] prolog_listing:most_general_goal(pi_to_head(_25916,_25918),_25912)
ERROR:   [13] prolog_listing:list_clauses(prolog_listing:pi_to_head(_25962,_25964),prolog_listing,[]) at /usr/local/lib/swipl/library/listing.pl:379
ERROR:   [11] prolog_listing:list_module(prolog_listing,[]) at /usr/local/lib/swipl/library/listing.pl:128
ERROR:    [9] toplevel_call(user:prolog_listing:listing) at /usr/local/lib/swipl/boot/toplevel.pl:1117
ERROR:
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.
   Exception: (14) prolog_listing:most_general_goal(pi_to_head(_25182, _25184), _25246) ?
WARNING: By typing Control-C twice, you have forced an asynchronous
WARNING: interrupt.  Your only SAFE operations are: c(ontinue), p(id),
WARNING: s(stack) and e(xit).  Notably a(abort) often works, but
WARNING: leaves the system in an UNSTABLE state

Action (h for help) ? exit (status 4)
1 Like

library(listing) was missing an import declaration. Fixed and pushed. For a decent user experience it is probably better to figure out what the autoloading issues are that you are dealing with. Without any details I have no clue.

For those wanting to see the commit.


@jan

I looked at the GitHub history for listing.pl trying to figure out what/when the code was broken for the example given. If you could shed some light on that it would help to better understand why it seems the bug has possibly been there for many months.

use git blame listing.pl, find the line adding most_general_goal/2 and see this is commit f24b5cf43d, Feb 10 2021 (and it is my fault :slight_smile: )

This works when disabling autoload, but the output was not what I expected. I expected the predicates from my workspace to be listed, in a form that can be saved to a file, which can be read in and qcompiled again.

With autoload enabled, I see this:

➜  src git:(master) ✗ swipl
Welcome to SWI-Prolog (threaded, 64 bits, version 8.5.3-21-gcc467667f-DIRTY)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit https://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- consult('facts.qlf').
true.

?- listing.
ERROR: /usr/local/lib/swipl/library/listing.pl:45:
ERROR:    library_directory/1: Unknown procedure: '$parms':cached_library_directory/3
Warning: /usr/local/lib/swipl/library/listing.pl:45:
Warning:    Goal (directive) failed: prolog_listing:use_module(library(settings),[setting/4,setting/2])
ERROR: /usr/local/lib/swipl/library/settings.pl:54:
ERROR:    prolog_exception_hook/4: Unknown procedure: prolog_stack:debug/3
ERROR:      However, there are definitions for:
ERROR:            prolog_stack:debug/0
Warning: /usr/local/lib/swipl/library/settings.pl:54:
Warning:    Goal (directive) failed: settings:use_module(library(arithmetic),[arithmetic_expression_value/2])
ERROR: /usr/local/lib/swipl/library/listing.pl:102:
ERROR:    prolog_exception_hook/4: Unknown procedure: prolog_stack:debug/3
ERROR:      However, there are definitions for:
ERROR:            prolog_stack:debug/0
ERROR: /usr/local/lib/swipl/library/listing.pl:104:
ERROR:    prolog_exception_hook/4: Unknown procedure: prolog_stack:debug/3
ERROR:      However, there are definitions for:
ERROR:            prolog_stack:debug/0
ERROR: /usr/local/lib/swipl/library/listing.pl:106:
ERROR:    prolog_exception_hook/4: Unknown procedure: prolog_stack:debug/3
ERROR:      However, there are definitions for:
ERROR:            prolog_stack:debug/0
ERROR: /usr/local/lib/swipl/library/listing.pl:108:
ERROR:    prolog_exception_hook/4: Unknown procedure: prolog_stack:debug/3
ERROR:      However, there are definitions for:
ERROR:            prolog_stack:debug/0
ERROR: /usr/local/lib/swipl/library/listing.pl:110:
ERROR:    prolog_exception_hook/4: Unknown procedure: prolog_stack:debug/3
ERROR:      However, there are definitions for:
ERROR:            prolog_stack:debug/0

:- dynamic'8701860C-F92A-495B-A0BF-C76316DE647C'/2.

ERROR: library_directory/1: Unknown procedure: '$parms':cached_library_directory/3
ERROR: prolog_exception_hook/4: Unknown procedure: prolog_stack:debug/3
ERROR:   However, there are definitions for:
ERROR:         prolog_stack:debug/0
ERROR: library_directory/1: Unknown procedure: '$parms':cached_library_directory/3
 ?

There is still no clue what is going wrong with autoloading.

It will surely be polluted. There are several predicates that for historical reasons live in the user module. If the .qlf file doesn’t contain a module you an switch to some new module using

?- module(my_module).

That at least avoids pollution.

Little clue. I don’t recall cached_library_directory/3 and cannot find it. listing/0 works fine for me on a clean environment, both with and without autoloading (after latest patch). Possibly facts.qlf contains stuff that corrupts the environment (like adding an incomplete definition of library_directory/1). You might be able to get better results using clause/2 and portray_clause/2 if this is caused by listing/0 trying to find relevant predicates.

I see - I have some work to do. Fortunately the file consists of predicates that all have uuids, and the rest. So I can filter on those- all 807 MB of them - and the rest. I must have missed the memo about modules. If I understand correctly, I now can have my ‘data’ and ‘code’ modules, and listing(‘data’). would give me only the data? That would make the effort worthwhile.

If you want to use listing/0 to dump all data I’d surely put all data in a module. You list the entire module using one of ?- data:listing. or ?- listing(data:_).

edit note that listing/0 is rather slow as it tries to make a nice human readable listing. If you just want data, using clause/2 to enumerate the data and dump them using write_canonical/2 or, possibly more readable, using write_term/3 with suitable options.

I hand-edited the offending lines out of the file. It behaves perfectly, and I must say - very, very fast. It generates the book, that I would start 10 years ago as an overnight job, as I look at it.

I am afraid I don’t understand enough to make your tips about clause/2 and write_canonical operational. I do agree that the performance of listing/0 is bad, to put a nice word to it. This used to be much faster? I implemented that in an app server and I can only remember that to be nearly instantaneous. I do need a mechanism to add the mappings and definitions that the user adds with assert and retract to the knowledge base, and up until now listing/0 did that job. I can, of course, log these user interactions to a relational database and merge them into a new knowledge base, but I somehow liked the previous mechanism in which I could ‘checkpoint’ it to a file in source form.

Could you perhaps show me an example of clause and write?

If you have the predicate, say p/1 you can use something along these lines (not tested).

  forall(clause(p(X), Body), write_clause(p(X) :- Body)).
write_clause(Head :- true) :-
    !,
    \+ \+ ( numbervars(Head, 1, _, [singletons(true)]),
              write_term(current_output, Head, [ full_stop(true), newline(true), numbervars(true), quoted(true)]) ).
write_clause(Head :- Body) :-
    \+ \+ ( numbervars((Head:- Body), 1, _, [singletons(true)]),
              write_term(current_output, (Head :- Body), [ full_stop(true), newline(true), numbervars(true), quoted(true)]) ).

I don’t think so. Maybe a little. If the clause is related to a file the current version will try to get access to the actual variable names. Old versions did not even try. The aim of portray_clause/1,2 is to produce an as pleasant as possible representation for humans, not to optimize on performance.