Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any reasonable way to embed a Prolog interpreter inside of a C program? [closed]

I would like to embed a Prolog interpreter within a C program, so that it can be used to evaluate business rules.

Both SWI-Prolog and GNU Prolog seem to hint at having such a feature, but both also seem to require the use of their own compiler and linker in order to do so, and don't have any clear examples or documentation of this usage - rather than providing a regular library to use and clear documentation.

What I'm searching for is a library that behaves similarly to how Python and Lua can be embedded in a C program, e.g.:

// Setup
PrologContext context = plNewContext();
plConsult(context, "businessRules.pl");

// Later in the program
if (plEvaluate(context, "can_view_page(%a)", path)) { ...
like image 416
Ethan McTague Avatar asked Dec 03 '20 01:12

Ethan McTague


People also ask

How does Prolog interpreter work?

Unlike many other programming languages, Prolog is intended primarily as a declarative programming language. In prolog, logic is expressed as relations (called as Facts and Rules). Core heart of prolog lies at the logic being applied. Formulation or Computation is carried out by running a query over these relations.

How do I exit Prolog interpreter?

If you want to exit SWI-Prolog, issue the command halt., or simply type CTRL-d at the SWI-Prolog prompt.

How do you check if an element is a list Prolog?

To check if a variable is bound to a list, you can use is_list/1 .

Are most Prolog implementations written in C or C++?

Aren't most prolog implementations written in C or C++? GNU Prolog is an open-source implementation of Prolog written in C. You can download the sources and peek inside :-) Hope this helps. I bet you'd get a lot out of Warren's Abstract Machine: A Tutorial Reconstruction, which discusses how to implement Prolog in a procedural language.

What can you do with a Prolog file?

Consulting prolog files into other prolog program techniques. So far we have seen that we can write a program and the query on the console to execute. In some cases, we print something on the console, that are written in our prolog code. So here we will see that writing and reading tasks in more detail using prolog.

How to write one character at a time in Prolog?

We can use put (C) to write one character at a time into the current output stream. The output stream can be a file or the console. This C can be a character or an ASCII code in other version of Prolog like SWI prolog, but in GNU prolog, it supports only the ASCII value. To use the character instead of ASCII, we can use put_char (C).

What is the easiest way to find the code for Prolog?

In terms of finding the code, the unification algorithm is easiest to find, then implementations with back chaining imbedded in applications. Finding a fully functional implementation of Prolog in a functional language with an REPL is the hardest.


3 Answers

Here is a small example that uses between/3.

#include <stdio.h>
#include <SWI-Prolog.h>

int main()
{
  char *argv[] = {"hello", "-q"};
  PL_initialise(2, argv);

  term_t a = PL_new_term_refs(3);
  PL_put_integer(a, 11); // First argument to between/3
  PL_put_integer(a+1, 17); // Second argument to between/3

  static predicate_t p;
  if(!p)
    p = PL_predicate("between", 3, NULL) ; // predicate between/3
  
  qid_t q = PL_open_query(NULL, PL_Q_NORMAL, p, a);
  int tmp;
  while(PL_next_solution(q)==TRUE){
    PL_get_integer(a+2, &tmp); // Third argument to between/3
    printf("%d\n", tmp);
  }
  PL_close_query(q);
  return 0;
}

Compile it using swipl-ld and execute

swipl-ld -o between between.c
./between
11
12
13
14
15
16
17

Another example if you want to load a file and then do a query.

#include <stdio.h>
#include <SWI-Prolog.h>

void consult_file(const char* filename){
  /* PL_initialse before calling. */
  predicate_t p = PL_predicate("consult", 1, NULL);
  term_t a = PL_new_term_ref();
  PL_put_atom_chars(a, filename);
  PL_call_predicate(NULL, PL_Q_NORMAL, p, a);
}

int main()
{
  char* argv[] = {"consult_file", "-q"};
  PL_initialise(2, argv);
  consult_file("digits.pl"); /* Load prolog file */

  static predicate_t p;
  /* third argument is module name if the predicate is in one.*/
  if(!p) p= PL_predicate("digit", 1, NULL); 
  int tmp; term_t a = PL_new_term_ref();
  qid_t q = PL_open_query(NULL, PL_Q_NORMAL, p, a);
  while(PL_next_solution(q)==TRUE){ /* All solutions */
    PL_get_integer(a, &tmp);
    printf("%d ", tmp);
  }

  return PL_halt(0);
}

With digits.pl file as follows we get the three numbers 1 2 3 as output.

digit(1).
digit(2).
digit(3).
like image 131
rajashekar Avatar answered Oct 17 '22 17:10

rajashekar


I can't speak for GNU Prolog but SWI-Prolog is definitely well-documented.

Note, that various Prolog implementations will have their own specific interfaces, nothing is standardized. The ISO standard says nothing (on second thoughts, all the better actually. It would probably be a mess set in stone; nobody seems to be implementing the standardized modules approach either).

The undertaking is certainly fraught with uninteresting implementation details, but this is about C. In no way are special compilers or linkers needed.

  • Embed (functionality written in) C code into Prolog: Write your predicate-implementing library code. Compile it to a shared object file. Load the shared object file from a Prolog process to make the predicates available to the Prolog processor. Example
  • Embed Prolog into (a program initially written in) C: Code the queries to the SWI-Prolog API and compile. The program should load the SWI-Prolog shared object into the (C-based) process.

But there is a much cooler way (i.e. one adapted to 2020 and how IT should actually work, namely as a bunch of communicating processes, each dedicated to a domain of the overall task): create a separate server process hosting Prolog to answer queries, (an SWI-Prolog engine, "Pengine") and access it via HTTP from your C-coded client process: Pengine. There is no example code on setting up the HTTP exchange from a C program though. It will depend on your HTTP client library.

like image 4
David Tonhofer Avatar answered Oct 17 '22 16:10

David Tonhofer


(not really an answer; just a few notes on GNU Prolog vs SWI-Prolog in this scenario that don't fit a comment)

GNU Prolog provides several advantages that may or may not be relevant in your particular case. First, it can generate executable code (something that SWI-Prolog cannot do) that you can easily distribute to anyone. Second, it have (out-of-the-box) fewer dependencies, which greatly simplifies deployment. For example, on my macOS system:

$ otool -L `which gprolog`
/opt/local/bin/gprolog:
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.50.4)

versus:

$ otool -L `which swipl`
/Users/pmoura/bin/swipl:
    /opt/local/lib/libtcmalloc_minimal.4.dylib (compatibility version 10.0.0, current version 10.3.0)
    @rpath/libswipl.8.dylib (compatibility version 8.0.0, current version 8.3.14)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.100.1)

$ otool -L /Users/pmoura/lib/swipl/lib/x86_64-darwin/libswipl.8.3.14.dylib
/Users/pmoura/lib/swipl/lib/x86_64-darwin/libswipl.8.3.14.dylib:
    @rpath/libswipl.8.dylib (compatibility version 8.0.0, current version 8.3.14)
    /opt/local/lib/libncurses.6.dylib (compatibility version 6.0.0, current version 6.0.0)
    /opt/local/lib/libform.6.dylib (compatibility version 6.0.0, current version 6.0.0)
    /opt/local/lib/libgmp.10.dylib (compatibility version 15.0.0, current version 15.1.0)
    /opt/local/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.100.1)
like image 2
Paulo Moura Avatar answered Oct 17 '22 16:10

Paulo Moura