How to call a predicate with arguments from command line and output its solution?

Hello!

My actual application is more complicated than the following illustrative predicate but I chose it as it is because it covers various features which I would need to handle. I tried around with initialization and some of the swipl attributes but cannot really get it to work and also can’t find good documentation on it.

Assuming this is stored in a file called app.pl:

t([X1, X2|[]], X3, Y) :- 
    Y1 is X1 + X2, 
    Y2 is 2 * X3, 
    Y = [Y1, Y2]
.

What I eventually want to be able to do is something like that (this is just plausible pseudo code):

swipl -f app.pl -c 't([1,2],3,Y)'

And then receive the response Y = [3,6] for further processing on STDOUT.

I don’t really want to introduce necessarily a main procedure. Though, it would also be interesting to see how that would work, too. But my eventual goal is to call individual predicates from Python or Bash for testing.

In fewer words, I want to emulate a single invocation in a swipl REPL session from the Linux command line.

I found a way to do it but I’m not super happy with the solution for obvious reasons.

➜ swipl -g "[app]." -g "t([1,2],3,Y), writeln(Y)" -g halt
[3,6]

It’s pretty hacky. I tried at least replacing -g "[app]." with -f app.pl but that failed. Also -F, -l, -s didn’t work for loading the database.

Kind Regards

Raffael

What’s “hacky” about this? I’ve seen lots of bash scripts that use bash -c, similarly for Python; it seems reasonable to do the same for Prolog (except Prolog has more control over the top-level, via the -g option).

As for -f … perhaps -f none -l app.pl does what you want? And/or use initialization/2 ?

First of all I made a mistake. Using -f app.pl does actually work:

> ➜ swipl -f app.pl -g "t([1,2],3,Y), writeln(Y)" -g halt
> [3,6]

That looks much better. I find it still a bit “hacky” because the invocation requires string processing beyond the predicate call; having to append "..., writeln(Y)". Also the explicit halt seems dubious :wink: My code smell detector is going off seeing that. But of course, it’s better than nothing.

pyswip also looks promising for a clean integration.

Regarding initialization. Am I right to assume that this would be relevant for declaring a main predicate which is called implicitely?

This wouldn’t be relevant for this use case as I intend to test isolated (sets of) predicates but might be useful if I want to turn this into an executable (chmod +x).

This is just a way of saying “don’t use the REPL and all its goodies” (the REPL is prolog/0). In other words, it’s a way of saying “this is a command line”, except it has more flexibility by allowing you to define your own REPL (or none).

Yes. And for this, you would load the program using just swipl ... app.pl rather than swipl .. -l appl.pl (-l loads the file without invoking anything specified by initialization/1 or initialization/2, although that isn’t spelled out in the documentation - @jan perhaps this could be clarified?)

See swipl -c and qsave_program/2.

1 Like

The current “recommended” way is

swipl -g "t([1,2],3,Y), writeln(Y)" -t halt app.pl

It would be possible to write a support file query.pl such that you can do e.g.

swipl query.pl app.pl “t([1,2],3,Y)”

query.pl would use initialization/2 to start the execution, get the query and print the results. What I think is still missing is a way to comfortably load a library like Python’s -m module That would allow to put query.pl in the library and run

swipl -m query app.pl "t([1,2],3,Y)"

Would this make sense? If it does, should -m lib terminate the option list, passing all remaining options to the application? In the above that would mean that the library must decide to load app.pl

Okay, that’s good to know. Thanks.

I’m not sure how query here would be different from t(...) but that might well be because I’m very new to Prolog and still mess up the terminology.

Generally, though, that looks great. But after a quick research I must say that my reference point Python isn’t doing this much different anyway. Seems like I was suffering from false memory here. Calculating sine would look like this.

python3 -c "import math;x=math.sin(1);print(x);"

Only thing different is the not required explicit halt.

swipl -m query ... would (when implemented), be the same as

swipl -g '[library(query)]' -- ...

The (not existing) library(query) would than handle processing additional Prolog files, running a query and printing the result. More in general, using a -m library we would have a more friendly commandline interface for many tasks. for example, this could install an extension pack.

swipl -m packs install mypack

You can also do

swipl -q -t "writeln(hello)"
hello

It is not recommended though as exceptions in the “toplevel” goal cause Prolog to restart it :slight_smile: That is what happens on an “uncaught exception”.

Possibly you’d want a --libs option and/or use an environment variable (PLLIBS), to specify the library search order. There’s already an option to disable packs (--packs, which is useful for testing), so the definition could get a bit messy.

That is supported using -p library:<dir>. The -p flag extends the search paths maintained by file_search_path/2.

This is mostly about avoiding horrible syntax such as

 swipl -g "[library(prolog_pack)]" ...

This is no fun to type on the commandline and when dealing with several layers of scripting in between, quoting this properly can be a nightmare. If we have some option to load a file from some search path, this file can use initialization/2 using main and take over processing the remainder of the commandline. That might be a convenient way to provide Prolog based commandline tools that is platform independent.

2 Likes