[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/sweeprolog b67e5b5e3d 029/166: DOC: Expand the manual sect
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/sweeprolog b67e5b5e3d 029/166: DOC: Expand the manual section about Querying Prolog |
Date: |
Fri, 30 Sep 2022 04:59:23 -0400 (EDT) |
branch: elpa/sweeprolog
commit b67e5b5e3db3d4810614cb7540081827cb6f467c
Author: Eshel Yaron <me@eshelyaron.com>
Commit: Eshel Yaron <me@eshelyaron.com>
DOC: Expand the manual section about Querying Prolog
---
README.org | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
sweep-tests.el | 6 ++--
sweep.c | 33 ++++++++++++++------
3 files changed, 111 insertions(+), 23 deletions(-)
diff --git a/README.org b/README.org
index 9c65dadfd9..415f821a81 100644
--- a/README.org
+++ b/README.org
@@ -89,21 +89,94 @@ The different parts of =sweep= are structured as follows:
: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)
diff --git a/sweep-tests.el b/sweep-tests.el
index c2dc790cab..072aaf0127 100644
--- a/sweep-tests.el
+++ b/sweep-tests.el
@@ -11,8 +11,8 @@
(should (equal (sweep-cut-query) t)))
(ert-deftest system:=/2 ()
- "Tests calling the Prolog predicate permutation/2 from Elisp."
- (should (equal (sweep-open-query "user" "system" "=" (list 1 2 3)) t))
- (should (equal (sweep-next-solution) (list '! 1 2 3)))
+ "Tests unifying Prolog terms with =/2 from Elisp."
+ (should (equal (sweep-open-query "user" "system" "=" (list 1 nil (list "foo"
"bar") 3.14)) t))
+ (should (equal (sweep-next-solution) (list '! 1 nil (list "foo" "bar")
3.14)))
(should (equal (sweep-next-solution) nil))
(should (equal (sweep-cut-query) t)))
diff --git a/sweep.c b/sweep.c
index bccb1ad40b..02fd5dd5f5 100644
--- a/sweep.c
+++ b/sweep.c
@@ -91,12 +91,21 @@ term_to_value_integer(emacs_env *eenv, term_t t) {
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;
@@ -142,12 +151,6 @@ term_to_value_blob(emacs_env *env, term_t t) {
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;
@@ -213,7 +216,7 @@ term_to_value(emacs_env *env, term_t t) {
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; */
@@ -232,6 +235,12 @@ value_to_term_integer(emacs_env *env, emacs_value v,
term_t t) {
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;
@@ -260,6 +269,8 @@ value_to_term(emacs_env *env, emacs_value v, term_t t) {
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);
@@ -347,10 +358,12 @@ sweep_open_query(emacs_env *env, ptrdiff_t nargs,
emacs_value *args, void *data)
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;
@@ -379,12 +392,14 @@ sweep_open_query(emacs_env *env, ptrdiff_t nargs,
emacs_value *args, void *data)
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
- [nongnu] elpa/sweeprolog 4ee4291703 018/166: TEST: Add ERT based tests, (continued)
- [nongnu] elpa/sweeprolog 4ee4291703 018/166: TEST: Add ERT based tests, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog 268df47cfc 021/166: More rpath tweaks, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog b92f25f764 030/166: Cleanup sweep.el, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog 972337d6d0 040/166: FIXED: accidentally left debugging remnants, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog 0de5109bf8 064/166: ENHANCED: add completion-at-point in sweep-mode, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog 5dfb1366e3 012/166: DOC: fix typo, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog d9546b9414 025/166: ENHANCED: make the prompts used in sweep-find-* customizable, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog e62d23140f 019/166: FIXED: Makefile setting SOEXT to dylib on linux hosts, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog 7c15ebc4f1 026/166: ENHANCED: annotate predicates with the summaries from the manual, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog 59b9dde951 028/166: DOC: Document sweep-pack-install, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog b67e5b5e3d 029/166: DOC: Expand the manual section about Querying Prolog,
ELPA Syncer <=
- [nongnu] elpa/sweeprolog 5455c53eaf 031/166: ENHANCED: Add optional "reverse" argument flag to sweep-open-query, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog ff13d97396 034/166: DOC: Add CUSTOM_ID properties to README.org headings where needed, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog 5fa0e16ee3 037/166: DOC: Document sweep_funcall/2, 3 in the manual, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog 66ac977deb 045/166: Make use of the new SWI-Prolog embedded GMP handling..., ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog 8f1275f113 044/166: Remove the swipl-devel git submodule, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog 5dcdec144d 052/166: PORT: use swipl --dump-runtime-variables to locate SWI-Prolog.h, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog b24f66da61 051/166: Add licensing information, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog 43e5cdaf91 054/166: ADDED: global keymap sweep-prefix-map, not bound by default, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog 239e205add 059/166: ADDED: sweep-mode, a major mode for editing Prolog code, ELPA Syncer, 2022/09/30
- [nongnu] elpa/sweeprolog d226bbb70c 063/166: ENHANCED: set per buffer module name in sweep-mode, ELPA Syncer, 2022/09/30