Importing from a script that has a main

I’m using: SWI-Prolog version: 8.1.24.

I want the code to import some_predicate without running it’s initialization predicate.

To reproduce: swipl

It runs hello world 2! and there seems no way to ignore the initialization of script2. Is it possible to ignore the main predicate of the other file? Of course, there are workarounds, but it would be nice to be able to import predicates from a script that has a main predicate. for the code to reproduce

This is a very odd setup/request. Still, a quick and dirty hack would be to change to:

:- initialization(main).

term_expansion((:- initialization(_)), []).

:- load_files("").

main :-
    format("Hello world!~n").

You would then get:

$ swipl
Warning: /Users/pmoura/Downloads/swi_initialization_bug-master/
Warning:    Redefined static procedure main/0
Warning:    Previously defined at /Users/pmoura/Downloads/swi_initialization_bug-master/
WEWHello world!

To be safe, you would likely want to delete the clause for term_expansion/2 above after loading the file.

P.S. Logtalk term-expansion mechanism provide a clean solution here as it allows loading a file while specifying the hook object (or hook module) used to expand it, without having the expansion rules affecting anything else.

Thanks for the hack!

I don’t think this is a very odd setup. It’s pretty normal to have two prolog files that could be run as scripts separately but still contain some predicates that you want to use as well.

In that case, maybe instead move those predicates to a separate file and then bring them to the scripts using the include/1 directive? That would be a better solution.


I agree that this will be the better and cleaner solution, but I still think it needs to be possible in SWI Prolog to handle this case.

That depends if by “possible in SWI-Prolog” means just what’s part of its distribution or includes third-party solutions that run on it. I still think that an include/1 based solution is the simplest and cleanest solution. The Logtalk solution I hinted about is also clean but overkill here:

:- module(no_init_hook, []).

term_expansion((:- initialization(_)), []).
term_expansion((main :- _), []).

Then in

:- logtalk_load('', [hook(no_init_hook)]).

Which gives:

$ swilgt -q
WEWHello world!
1 Like

There is. See initialization/2 rather than ISO initialization/1. Notably, initialization(Goal, main) defines the entry point of your program. There is only one such thing (see docs for which one wins if there are more). Most importantly,
the entry point is executed on swipl, but not on swipl -l or loading the file in swipl using ?- [script].

This has been added relatively recently, not sure it is in the stable or you need the devel versions.

edit Before the initialization(Goal,main) alternative I tended to have a that loads the application and a that loads and calls the entry point.

For debugging, I use swipl -g my_program:main -l -- args. This also plays nicely with make/0. ( has the directive :-initialization(main,main)..

When not debugging, I compile the program and use my_program.qlf args.

Dear Rob,

I never liked SWI’s (Jan’s) choice of main/0 as the default entry point.

pack(upsh) looks first for /1,0 of script .pl .

This leads to far fewer classes.

On the other hand, I don’t like what you are trying to do either.
If you have code that is needed by more than one scripts, then put the common bits somewhere else.

Packs are really good places for such things.
There is nothing to stop you from having private ones.

One limitation of SWI is that uses monolithic packs. And that discourages
catch-all/ medley packs.

Pack(lib) can be used to provide on-demand loading of bits of packs.
For example see pack(stoics_lib).
Where you can load into only the bits you need with something like
:- lib(stoics_lib:en_list/2).


Nicos Angelopoulos