Syntax for Calling Prolog from C

Here’s the issue:

I have a Prolog predicate doStuff(A, B, C) in my database.pl file, where A and C are inputs (it’s tacky but there’s a reason for it).

I have a C file to call this, and I’m able to compile and link them together without error. But when I actually try and run the executable, I get the following error:

Welcome to SWI-Prolog (threaded, 64 bits, version 10.0.2)
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).

ERROR: [Thread main] '$c_call_prolog'/0: Unknown procedure: doStuff/3
   Exception: (1) doStuff(31, _13194, 15) ? creep

From the error message, SWI-Prolog is booting, it is correctly sending my predicate with the inputs where they belong and a variable where the output will be. But it seems like SWI-Prolog isn’t loading my database file.

I’ve tried rewriting my C file a number of ways, including:

predicate_t pred = PL_predicate("doStuff", 3, "user"); 

OR

// I tried making the database a module, and then doing:
predicate_t pred = PL_predicate("doStuff", 3, "module_name");

OR

predicate_t pred = PL_predicate("doStuff", 3, "path-to-file/database.pl");

I’m not sure if it’s relevant, but the term inputs are as follows:

term_t term0 = PL_new_term_refs(3);          
term_t term1 = term0 + 1;                                   
term_t term2 = term1 + 1;                                               

PL_put_integer(term0, args[0]);        
PL_put_variable(term1);               
PL_put_integer(term2, args[1]);      

int ret_val = PL_call_predicate(NULL, PL_Q_NORMAL, pred, term0)

Since things are going without error except for the predicate call, and since the predicate itself seems to be formatted correctly in the error message (and spelled correctly), it seems like I don’t know how to get the C file to load the database before executing the predicate call.

I’ll add that when I use swipl in the terminal and load the database, doStuff() works perfectly, so it isn’t an error with the predicate itself either.

Any help with this would be greatly appreciated!

How are you trying to load the Prolog file holding doStuff/3? You should either do so from Prolog or have C make a call that makes Prolog load the data. That means call e.g. consult/1 using the file as argument from C using PL_call_predicate().

Yep, that’s what I was missing!

On a related note, aside from writing to console while Prolog is running, is there a way to pass the outputs of a predicate back to C? None of my tests with printf() are printing the variable from the terms I sent to Prolog, whether Prolog is running or not. I’ve also tried assigning their values to a C variable while Prolog is still running, and printing them when Prolog closes, but all to no avail.

If you call a predicate from C you normally want its answer in C, no? This implies you call one of the extraction predicates (PL_get_*()) to get what you want. If you want to print from C, you can so so using PL_write_term() (requires #include <SWI-Stream.h>). Except for debugging, I do not see the point and for debugging I’d normally add debug/3 statements to the Prolog side.

Debugging is why I bothered putting the write statements in. That’s what I needed though, thanks!

This is your regular reminder that the C++ API is easier to use and less error-prone than the C interface (if you know C++, of course). There are code examples in the documentation (and in the distributed source) that should cover your situation; if there aren’t, please tell me and I’ll add some.

The C interface can be a bit tricky to get right, as you’ve experienced. :slight_smile:

Of course!

I’m once again going through relearning C++ (basically because I was writing C-like C++ instead of more modern and proper C++), plus my use of C is mainly as glue between Prolog and MATLAB, because I want to plot the output of my Prolog predicates. While this could definitely be done with C++ and something like Matplot++, I’m just not at that comfort level yet, so I was knowingly avoiding it for the time being.

In the future I will be certain to make use of it!

You may consider the web version (SWISH). That comes with rather simply JavaScript C3 charts, but also connects to R, which allows for pretty fancy plots. Integrated into SWISH notebooks that could be what you are looking for …

Note that you can run SWISH locally and disable its sandbox so you have a full Prolog system with a web interface.

Is there some guidance on how to do that?