Converting a term into executable emacs-lisp expression

I made a small revision on an old codes of mine, which converts a prolog term into an executable emacs-lisp expression. Here is some self-explanatory sample queries:

% ?- elisp:term_to_lisp_string(f(), X).
%@ X = "(f )" .
% ?- elisp:term_to_lisp_string(list(1,2,3), X).
%@ X = "(list 1 2 3 )" .
% ?- elisp:term_to_lisp_string(progn(a, b, c), X).
%@ X = "(progn a b c )" .
% ?- elisp:term_to_lisp_string(cond([a,b],[b,c]),  X).
%@ X = "(cond (a b )(b c ))" .
% ?- elisp:term_to_lisp_string(defun(f, [a,b], +(a, b)),  X).
%@ X = "(defun f (a b )(+ a b ))" .

This converter is used in my “emacs-prolog” on top of emacs-lisp, which works fine for basic editing region of emacs buffer.

It is straightforward to use this converter for handling emacs buffer by calling functions in emacs-lisp. Details is lengthy, so should be omitted here.

% ?- elisp:lisp(sort(list(4, 8, 21, 17, 33,  7,  21, 7), #(>)), V).
['V'=[33,21,21,17,8,7,7,4]]

% ?- elisp:lisp(+(1, 2, 3), Y).
['Y'=6]

% ?- elisp:lisp(setq(uuu, +(1,2,3)), V).
['V'=6]

% ?- elisp:lisp(progn(setq(uuu, +(1,2,3)), *(uuu, uuu)), V).
['V'=36]

# is for `quote`.
% ?- elisp:lisp(append(cons(#(x),#([a,b])), #([u,v])), R).
['R'=[x,a,b,u,v]]
% # is reserved for quote.
term_to_tokens(X, ['('|Y], Z):- is_list(X), !,
		  term_to_tokens_with_closing(X, Y, Z).
term_to_tokens(X, [X0|Y], Y):- atom(X), !, atom_string(X, X0).
term_to_tokens(X, [X0|Y], Y):- atomic(X), !, term_string(X, X0).
term_to_tokens(#(X), Y, Z) :- term_to_tokens([quote, X], Y, Z).
term_to_tokens(X, Y, Z) :-
	compound_name_arguments(X, F, Args),
	term_to_tokens([F|Args], Y, Z).

term_to_tokens_with_closing([], [')'|Y], Y).
term_to_tokens_with_closing([A|B],  X, Y):-  term_to_tokens(A, X, Z),
	term_to_tokens_with_closing(B, Z, Y).

I am afraid that at this time of modern technology, “emacs-prolog” is obsolete or deprecated. Although Pcemacs sounds close to the emacs-prolog. Unfortunately it seems not work
on GnuEmacs.

1 Like

I’m not sure but it sounds like Sweep can be of help here. For one, it allows Prolog to invoke Elisp.
(It also allows Elisp to call Prolog, which can in turn call Elisp, and so on.)

Could you shed some more light on “emacs-prolog” and what it does?

Sound great! Which makes me sure my work is really obsolete.

I hope the following two simple examples will help you what I have in mind for emacs-prolog on top of emacs-lisp.

handle([choose, files]) -->
	{choose_files(X), insert("\n", X, X0) },
	 peek(X0).
handle([enum]) --> region,
	snippets:environment(enumerate),
	overwrite.

The first region handler displays POSiX file paths which are choosen by the user via osacscript.

The second one is to edit latex enumerate environment for items in the region.

% region
a

b

c

Output in the region.

\begin{enumerate}
\item a
\item b
\item c
\end{enumerate}

Emacs shortcut “C-l” is prepared to invoke handlers with completing arguments.

I have skimmed the doc. It may take time for me to digest it so that I can move my “emacs handlers” to Sweep. Sorry for my poor reading. I am a user of Ediprolog mode, which I never read the doc about ediprolog.el, which is still a blackbox for me. So far it’s DWIM facility was enough for my using the mode. Do you have some advice for those who are (too much ) familiar
with Ediprolog mode to move to Sweep ?

EDIT

Afer installing sweeprolog by M-x package-list-packages and inserting the two lines in init.el:
(require 'sweeprolog)
(setq sweeprolog-swipl-path “/usr/local/bin/swipl”)

with ediprolog lines commenting out.

I put a new file test.pl
test.pl:

test:- writeln("hello world.\n").

My first question is how to compile the test.pl by sweep, and then
how to run the query ?- test.

Thanks.

1 Like

First, make sure that sweeprolog-mode is enabled in the test.pl buffer. You can have Emacs use this mode for Prolog buffers automatically by adding something like the following to your config:

(add-to-list 'auto-mode-alist '("\\.plt?\\'"  . sweeprolog-mode))

In sweeprolog-mode, you can use C-c C-l to load the current buffer.
To run your code, use the integrated top-level. The simplest way to do that is to type C-c C-t in the source code buffer, that’ll pop up the top-level where you can then type test. and hit enter just like you would in a regular top-level.

Thanks. “Hello World.\n” runs !

However, it runs in a different way from Ediprolog mode, which runs queries in the buffer with typing C-c C-e. Has Sweep a switch for mode for running dierectly the query in the buffer like Ediprolog mode ? I guess it seems out of design principle of Sweep.

Anyway thanks. Sweep is impressive. now I want read more the Sweep doc.

Indeed, in Sweep we use separate buffers for writing and evaluating code.
BTW if you find this as a limitation, I’d be interested to hear why. It shouldn’t be too hard to extend Sweep with a way of evaluating example queries that appear in comments similarly to what ediprolog provides, but I’m not sure I fully understand the motivation.

Thank you!

It’s my custom to add sample queries before predicate definitions like this, which is useful to remind me of functions later and by running the query.

% ?- elisp:term_to_lisp_string(f(), X).
%@ X = "(f )" .
% ?- elisp:term_to_lisp_string(list(1,2,3), X).
%@ X = "(list 1 2 3 )" .
% ?- elisp:term_to_lisp_string(prog(a, b, c), X).
%@ X = "(prog a b c )" .
% ?- elisp:term_to_lisp_string(cond([a,b],[b,c]),  X).
%@ X = "(cond (a b )(b c ))" .
% ?- elisp:term_to_lisp_string(defun(f, [a,b], +(a, b)),  X).
%@ X = "(defun f (a b )(+ a b ))" .
term_to_lisp_string(X, Y):- term_to_tokens(X, Y0, []),
	tokens_to_string(Y0, Y).

Ediprolog mode has a merit to dispense cut and paste typing between two buffers (source and toplevel ones).

I would appreciate if such “minor request” of a lazy person could be accepted.

What is the exclamation symbol (!) displayed at the beginning of predicate definition,
which is in green color ?

I use key-chord package, and jj,bb,ii, MM,for example are defined to do special actions on the buffer in Ediprolog mode. For instance, bb is defined to do qcompile the current buffer and
make it current module looking at the directive at the beginning line (:- module(–)).
I gives module name often at random, and often forget it easily.

When I move finally to Sweep in the future, I have to update prolog-mode to sweeprolog-mode.

Thus there may be small things to ask and to be updated for this transition, which take some time.
At this moment, I can only hope it is as short time as negligible to solve by myself.

To be honest, I am quite new to webassembly technology, which is a half of the motivation
for this transition to learn.

I can see how having such comments (along with a convenient way to create them) may be useful.
I’ve pushed a new version of Sweep that includes a command for that. (Note that It usually takes about a day for the Emacs package archive to pick up and publish the new version.)
This new command lets you create such example usage comments without having to copy-paste and format top-level transcripts manually.
See the accompanying manual section for full details.

These are Flymake diagnostic indicators. They indicate that there’s a diagnostic (error, warning or note) for some part of that line. Sweep enables these by default, you can change that by customizing sweeprolog-enable-flymake.

I’m not sure I understand the connection to WebAssembly, is this regarding Sweep? FWIW Sweep is not implemented with WebAssembly, it loads the regular SWI-Prolog (binary) shared library as an Emacs dynamic module and integrates the two through their C APIs.

Thanks. It seems that any possible questions of mine is answered in the manual.
From now on, I shoud keep silent before consulting it.

Sorry, it’s my fault, which perhaps comes from my confusion with webassmbly on browsers.

BTW, transition from the current emacs handlers of mine based on start-process of emacs-lisp
to that on Sweep should be easy, because basic idea of the handler is to send prolog goal to prolog from emacs-lisp, and S-expression from prolog to emacs-lisp. According to your related comment, such send/receive should be easy, though I am slow in rewriting codes on
what looks clear and easy in my mind.

Thank you for really quick push.

BTW, is the toplevel window always necessary?

As for Ediprolog mode, it is not, but the current buffer works also as the toplevel window,
which is covenient, for example, particularly when the query is long and complex with multiple lines, and the user wants to run the query multiple times with some experimental small changes.

Suppose ediprolog mode.
A region (1) in a prolog-mode buffer with the cursor at some point in the first line. Hit dwim(do what I mean) key C-c C-e then the region updated to (2)

(1) Region

% ?- writeln([somethinglong,
% somethinglong,
% somethinglong,
% somethinglong
% ]).

(2) updated Region with answer appended.

% ?- writeln([somethinglong,
% somethinglong,
% somethinglong,
% somethinglong
% ]).
%@ [somethinglong,somethinglong,somethinglong,somethinglong]
%@ true.

I am afraid this feature is not easy for Sweep, but I thought it is better for Sweep to put a note
on “toplevel window-less” Ediprolog mode.

Anyway thanks a lot.

EDIT: What am I missing ?

I put the sample elisp codes (1) in the manual on Emacs scratch buffer, and load the sweeprolog codes (2). Then I did M-x eval-region on the region (1), but to see nothing happen. I am surely missing something basic on how to use of Sweeprolog.

Any advice on what I am missing woul be appreciated. Thanks.

(1) This elisp codes is taken from the manual on sample query.

     (sweeprolog-open-query "user" "lists" "permutation" '(1 2 3 4 5))
     (let ((num 0)
           (sol (sweeprolog-next-solution)))
       (while sol
         (setq num (1+ num))
         (setq sol (sweeprolog-next-solution)))
       (sweeprolog-close-query)
       num)

(2) I check this prolog codes works as ordinal prolog codes.

% ?- permutation([a,b,c], X).
user:permutation([], []).
user:permutation([X|Xs], Ps):- permutation(Xs, Qs),
	insert_elem(X, Qs, Ps).
%
user:insert_elem(X, As, [X|As]).
user:insert_elem(X, [A|As], [A|Bs]):- insert_elem(X, As, Bs).