Command line scripts

Following How to call a predicate with arguments from command line and output its solution? and Symbolic links and real file names [mainly Windows Platform] and considering that in XSB the command line xsb name runs name.P from its library and considering that swipl name is simply an error, I think there is room for some improvement.

First, I was suggesting -m name, similar to Python. I think that can be simpler and cleaner. Right now, I’m considering

 swipl [pl-option ...] [search-path:]name ...

to mean load search-path(name) and make … available as argv. As there are a lot of files in the library search path and most are unsuitable for using this way as they do not process commandline arguments, I propose a new search path apps that would default to swi(apps) and allow each package to add apps. So we can make

 swipl pack ...
 swipl query ...

… etc. This approach easily runs on any platform. Just using the defaults would allow big apps to be compiled to .qlf. We could also define an extension such that we can create saved states in the app dir for fastest startup.

Normally, such a script should use this to get started

:- initialization(mystart, main).

I wonder what to do if this is missing. One option could be to simply start the normal REPL, another to simply terminate or complain that it doesn’t know how to start? Just dump into the REPL loop of course allows you do to e.g.

  swipl library:scasp

which would be nice for libraries that are not autoloaded but you may want to use interactively.

Opinions? Improvements? Other options?

2 Likes

I’ve written a couple of Unix filters using SWI-Prolog, and found the “Convert a CSV with column names to JSON” example in the documentation at SWI-Prolog -- (initialization)/2 really helpful.

While using < inputfile myfilter.pl rather than myfilter.pl inputfile works fine using the example as a template, I haven’t figured out how to get myfilter.pl <<<$output_from_last_filter to work in SWI-Prolog.

So a way to write PrologScript files that meet all the “standard” Unix filter conventions would be great. I suspect it probably can already be done, I just don’t know how.

under Windows, there are Named Pipes, you can use.
I come from the Linux Fraction, but used Windows at this Time.
I have install the MSYS2 MinGW32- / 64-Bit Environment - This is like Cygwin a Emulatetion of the BASH Shell with some Tools that you know from the Command Line under the Linux Terminal.
You can use this Shell, if you want to automate Things (like using your Filters - that are in my Eyes are Tools that you send over Pipes like: # echo “hello world” | awk ‘{print $2}’ which bring as Result: # world on Terminal Display Device.
Feel free for asking…

I think starting the REPL will not be good, because the end user is expecting it to behave just like a normal command line program. So the proper option, imho, is to exit with an error message and and exit code different from 0 just like all command line programs normally do.

Just to clarify: swipl -m name would be essentially the same as swipl $(swipl-lookup name), where swipl-lookup is

swipl -g "absolute_file_name(library(name), X, [access(read), file_type(prolog)]), writeln(X)" -t halt

?

BTW, the “man” page for swipl could do with some cleanup … there doesn’t seem to be an obvious order to the various options and I find it difficult to find an option, even when I know the feature that I’m looking for. (Are there any tech writers in this group?)

Agreed. Python has an implicit “main” (usually with an if __name__ == '__main__'); C/C++ requires a main() function, etc.

Why not treat the name the same way that load_files/2 does? So, you could write swipl ... 'library(name)' without the need for a -m option. (Although it might look a bit strange to non-Prologers). From looking at the default settings for file_search_path/2, it seems that only library is meaningful for loading files (perhaps pack also?), so treating name as whatever absolute_search_path/2 gets for name or library(name) might make sense (or might be confusing, which is possibly why Python has -m).

That is more or less what I propose. swipl [search-path:]name uses the same logic as load_files(SearchPath(Name)), where I propose app as default search path. From there on, there are few choices (I hope). Basically only how we call “main”? As we already have initialization/2 of “kind” main, I propose to use that. Applications that wish to run the Prolog REPL loop can do so explicitly from the initialization/2 goal. See library(main).

This still requires swipl in from of the cli command. That is a bit of a pity. It does provide platform independence, make it easy to add cli commands to control the Prolog environment, allow packs to add new cli commands, etc. And, it does all that without requiring the user to adjust PATH, create directories, etc.

Python programs still require python (or python3) in front of the CLI commands, so I don’t see this as a big problem. And there’s always qsave_program/2, if you want to get rid of the swipl.

Hi Jan,

pack(upsh) has a few relevant features.

upsh Lib:Pred
will load library(Lib) and call ?- Pred. (or Pred(ListOfArgs))

The mechanism you propose is more general, but looses a bit of the simplicity. My private code is either simple enough to be a single script which goes to ~/bin/cline_upsh or complex enough to go to a pack dir, which remains private until it is mature enough to go public. Bottom line is, there is no need to use anything else apart from packs :slight_smile:

You could go “more abstract” by creating a registry of Preds in Libs and do away with Lib: but I never felt a need for that relating to scripts. pack(lib) does utilise these if they exist, but in the end i switched to breaking interface preds of a pack into their own file, so it is trivial to locate them by looking at pack/src/<pred_name>.pl . (A complex enough example is pack(stoics_lib).)

upsh will also load Local.pl if this is the only .pl file in current dir (you could have a new flag or modify behavior of -f -l )

upsh Script.pl
also looks at script locations to find Script.pl
~/bin/cline_upsh/
and Pack/scripts/
[For Pack in all installed packs.]

In addition upsh will convert args from cli friendly to Prolog terms args.
Finally my upsh scripts that take os objects as args take the convention that atomic args are files to operate on, while Options that modulate behaviour are terms (eg prefix=testo at cli, which is translated to prefix(testo) in the Prolog call).

Regards

Nicos Angelopoulos

https://stoics.org.uk/~nicos/
https://stoics.org.uk/~nicos/sware/upsh

This is indeed a very simple design that deals with a large subset of the cases and allows for multiple toplevel goals per file. As you say, it is also a bit more limited, notably in commandline parsing.

Many commands have stopped loading some file from the current directory for security reasons. Also SWI-Prolog used to load .plrc from the current dir long ago. Of course, there are still exceptions such as make. They require a file in the current directory though.