:CUSTOM_ID: querying-prolog
:END:
-=sweep= provides the Elisp function =sweep-open-query= for initiating
-Prolog queries. To examine the results of the query, the function
-=sweep-next-solution= is used. When no more solutions are available, or
-when otherwise further solutions are not required, the query must be
-closed with either =sweep-cut-query= or =sweep-close-query=.
-
#+FINDEX: sweep-open-query
+=sweep= provides the Elisp function =sweep-open-query= for invoking Prolog
+predicates. The invoked predicate must be of arity two and will be
+called in mode =p(+In, -Out)=, i.e. the predicate should treat the first
+argument as input and expect a variable for the second argument which
+should be unified with the some output. This restriction is placed in
+order to facilitate a natural calling convention between Elisp, a
+functional language, and Prolog, a logical one.
+
+The =sweep-open-query= function takes four arguments, the first three
+are strings which denote:
+- The name of the Prolog context module from which to execute the
+ query,
+- The name of the module in which the invoked predicate is defined,
+ and
+- The name of the predicate to call.
+
+The fourth argument to =sweep-open-query= is converted into a Prolog
+term and used as the first argument of the predicate (see [[Conversion
+of Elisp objects to Prolog terms]]).
+
#+FINDEX: sweep-next-solution
-#+FINDEX: sweep-cut-query
-#+FINDEX: sweep-close-query
+The function =sweep-next-solution= can be used to examine the results of
+a query. If the query succeeded, =sweep-next-solution= returns a cons
+cell whose =car= is either the symbol =!= when the success was
+deterministic or =t= otherwise, and the =cdr= is the current value of the
+second (output) Prolog argument converted to an Elisp object (see
+[[Conversion of Prolog terms to Elisp objects]]). If the query failed,
+=sweep-next-solution= returns =nil=.
-As an example, we show an invocation of the non-deterministic
-predicate =lists:permutation/2= from Elisp, which yields the number of
-different permutations of the list =(1 2 3 4 5)=:
+#+FINDEX: sweep-cut-query
+#+FINDEX: sweep-close-query
+=sweep= only executes one Prolog query at a given time, thus queries
+opened with =sweep-open-query= need to be closed before other queries
+can be opened. When no more solutions are available for the current
+query (i.e. after =sweep-next-solution= returned =nil=), or when otherwise
+further solutions are not of interest, the query must be closed with
+either =sweep-cut-query= or =sweep-close-query=. Both of these functions
+close the current query, but =sweep-close-query= also destroys any
+Prolog bindings created by the query.
+
+** Conversion of Elisp objects to Prolog terms
+
+=sweep= converts Elisp objects into Prolog terms to allow the Elisp
+programmers to specify arguments for Prolog predicates invocations (see
+=sweep-open-query=). Seeing as some Elisp objects, like Elisp compiled
+functions, wouldn't be as useful for a passing to Prolog as others,
+=sweep= only converts Elisp objects of certain types to Prolog, namely
+we convert /trees of strings and numbers/:
+
+- Elisp strings are converted to equivalent Prolog strings.
+- Elisp integers are converted to equivalent Prolog integers.
+- Elisp floats are converted to equivalent Prolog floats.
+- The Elisp =nil= object is converted to the Prolog empty list =[]=.
+- Elisp cons cells are converted to Prolog lists whose head and tail
+ are the Prolog representations of the =car= and the =cdr= of the cons.
+
+** Conversion of Prolog terms to Elisp objects
+
+=sweep= converts Prolog terms into Elisp object to allow efficient
+processing of Prolog query results in Elisp (see =sweep-next-solution=).
+
+- Prolog strings are converted to equivalent Elisp strings.
+- Prolog integers are converted to equivalent Elisp integers.
+- Prolog floats are converted to equivalent Elisp floats.
+- A Prolog atom =foo= is converted to a cons cell =(atom . "foo")=.
+- The Prolog empty list =[]= is converted to the Elisp =nil= object.
+- Prolog lists are converted to Elisp cons cells whose =car= and =cdr= are
+ the representations of the head and the tail of the list.
+- Prolog compounds are converted to list whose first element is the
+ symbol =compound=. The second element is a string denoting the functor
+ name of the compound, and the rest of the elements are the arguments
+ of the compound in their Elisp representation.
+- All other Prolog terms (variables, blobs and dicts) are currently
+ represented in Elisp only by their type:
+ + Prolog variables are converted to the symbol =variable=,
+ + Prolog blobs are converted to the symbol =blob=, and
+ + Prolog dicts are converted to the symbol =dict=.
+
+** Example - counting solutions for a Prolog predicate in Elisp
+
+As an example of using the =sweep= interface for executing Prolog
+queries, we show an invocation of the non-deterministic predicate
+=lists:permutation/2= from Elisp where we count the number of different
+permutations of the list =(1 2 3 4 5)=:
+
+#+name: count-list-permutations
#+begin_src emacs-lisp
(sweep-open-query "user" "lists" "permutation" '(1 2 3 4 5))
(let ((num 0)
emacs_value v = NULL;
int64_t l = -1;
if (PL_get_int64(t, &l)) {
-
v = eenv->make_integer(eenv, l);
}
return v;
}
+static emacs_value
+term_to_value_float(emacs_env *eenv, term_t t) {
+ emacs_value v = NULL;
+ double l = -1;
+ if (PL_get_float(t, &l)) {
+ v = eenv->make_float(eenv, l);
+ }
+ return v;
+}
+
emacs_value
term_to_value_string(emacs_env *eenv, term_t t) {
char * string = NULL;
return env->intern(env, "blob");
}
-emacs_value
-term_to_value_float(emacs_env *env, term_t t) {
- (void)t;
- return env->intern(env, "float");
-}
-
emacs_value
term_to_value_compound(emacs_env *env, term_t t) {
atom_t name = 0;
case PL_BLOB:
return term_to_value_blob(env, t);
case PL_FLOAT:
- return term_to_value_blob(env, t);
+ return term_to_value_float(env, t);
default:
/* ethrow(env, "Prolog to Elisp conversion failed"); */
/* return NULL; */
return PL_put_int64(t, l);
}
+int
+value_to_term_float(emacs_env *env, emacs_value v, term_t t) {
+ double l = env->extract_float(env, v);
+ return PL_put_float(t, l);
+}
+
int
value_to_term_list(emacs_env *env, emacs_value v, term_t t) {
int r = -1;
r = value_to_term_integer(env, v, t);
} else if (env->eq(env, vt, env->intern(env, "cons"))) {
r = value_to_term_list(env, v, t);
+ } else if (env->eq(env, vt, env->intern(env, "float"))) {
+ r = value_to_term_float(env, v, t);
} else r = -1;
} else r = PL_put_nil(t);
char * c = NULL;
char * f = NULL;
term_t a = PL_new_term_refs(2);
+ emacs_value r = enil(env);
(void)data;
(void)nargs;
+
if (PL_current_query() != 0) {
ethrow(env, "Prolog is already executing a query");
goto cleanup;
o = a+1;
+ r = et(env);
+
cleanup:
if (c != NULL) free(c);
if (m != NULL) free(m);
if (f != NULL) free(f);
- return et(env);
+ return r;
}
static emacs_value