Is there a way to use module/2 in ECLiPSe Prolog? - prolog

In SWI-Prolog, I am using code such as at the beginning
of a module text file:
:- module(foo, [bar/2]).
:- use_module(library(jack)).
I don't want to change my code. How can I neverthelss use
ECLiPSe Prolog (*). Is there some library that defines a
module/2 directive in ECLiPSe Prolog?
Best Regards
(*)
http://eclipseclp.org/

You can compile Prolog module that uses SWI-Prolog module system using Logtalk for use with ECLiPSe (or any other of the supported Prolog compilers, including those that don't provide a module system).

The following code defines a macro that maps module/2 into module/3 directives:
:- export macro((:-)/1, translate_directive/2, [top_only]).
translate_directive(
(:- module(Module, Exports)),
(:- module(Module, Exports, [swi]))
).
Compile (or import) this before compiling the module written for SWI. Note that the 3rd argument of module/3 must contain a language module, corresponding to the dialect your module is written in. I have used swi here, other choices would be quintus, iso or ECLiPSe's native eclipse_language.

No, there are only module/1 and module/3.
You an see the list of all what available here: http://eclipseclp.org/doc/bips/fullindex.html

SWI-Prolog (an others) module/2 directives can be replaced on ECLiPSe by module/1 + export/1 directives as you likely already found out. Also both SWI-Prolog and ECLiPSe support conditional compilation directives and the dialect flag. This should provide you with another alternative (not tested) for using the same Prolog files with both systems:
:- if(current_prolog_flag(dialect, swi)).
:- module(foo, [p/1]).
:- elif(current_prolog_flag(dialect, eclipse)).
:- module(foo).
:- export(p/1).
:- else.
...
:- endif.

Related

Dealing with dynamic predicates that cause compilation failures

I am attempting to run an example GNU Prolog program used as an example during my course work. The code is pulled directly from https://www.cpp.edu/~jrfisher/www/prolog_tutorial/2_17pl.txt and was shown working at one point by my professor.
However, when I run the provided example code, I get the following compilation warning:
| ?- consult('C:/Users/Chase/Desktop/Prolog files/newAnimal.pro').
compiling C:/Users/Chase/Desktop/Prolog files/newAnimal.pro for byte code...
C:/Users/Chase/Desktop/Prolog files/newAnimal.pro:74:12: syntax error: . or operator expected after expression
1 error(s)
compilation failed
The line that is keeping the program from compiling correctly is:
:- dynamic yes/1,no/1.
Which I read up on here: https://www.swi-prolog.org/pldoc/man?predicate=dynamic/1
However, despite attempting to rewrite and reformat the section, I could still not get it to compile.
Any help on why the provided code may not be running?
I am using a Windows GUI GNU Prolog console V1.4.5
The ISO Prolog standard doesn't require dynamic(or multifile or discontiguous) to be declared as an operator. A few systems do it (e.g. SWI-Prolog like you mentioned) but not GNU Prolog. Thus, to ensure code portability, avoid using dynamic as an operator. Write instead:
:- dynamic(yes/1).
:- dynamic(no/1).
Or:
:- dynamic((yes/1, no/1)).
Or:
:- dynamic([yes/1, no/1]).
These are the standard conforming alternatives for declaring multiple predicates as dynamic.
Also, GNU Prolog have a fine manual (part of its installation) which you should refer to when using GNU Prolog.

Prolog, listing/1, Built-in System Predicates, SWI-Prolog 7.4.2

I'm trying to get the definitions for a few built-in predicates using SWI-Prolog 7.4.2. Specifically, split_string/4.
explain/1 returns:
system:split_string/4 is a built-in predicate
Summary: ``Break a string into substrings''
true.
listing/1 returns:
Foreign: system:split_string/4
true.
I've checked the System.pl file, but I cannot seem to find the definition. Is this possible at all?
SWI-Prolog is C based. Look for *.c in github, more specifically at this source.

Prolog term_expansion not working

I am trying to perform the following term_expansion with swipl:
a(asda).
a(astronaut).
term_expansion(a(X),b(X)).
But it does not work, i.e. there is no b/1 consulted. I have tried a few variations:
term_expansion(a(X),[b(X)]).
user:term_expansion(a(X),b(X)).
user:term_expansion(a(X),[b(X)]).
user:term_expansion(user:a(X),[user:b(X)]).
None of which works. What is the problem?
As explained by #mat, you need to define the term_expansion/2 predicate before the clauses you want to expand are loaded. Also, the term_expansion/2 predicate is a multifile and dynamic predicate defined for the user pseudo-module. Thus, you should write:
:- multifile user:term_expansion/2.
:- dynamic user:term_expansion/2.
user:term_expansion(a(X), b(X)).
This will ensure that your expansion code will work if you move it into a module.
If portability to other Prolog systems with a term-expansion mechanism (which, btw, is far from standard), than consider moving the term-expansion code to its own file, loaded before the source files you want to expand.

Workaround ensure_loaded/1 GNU Prolog?

Is there a workaround to make ensure_loaded/1 work
in GNU Prolog as it works in many other Prolog systems?
The goal is to have a preamble so that the rest of
code can use ensure_loaded/1 independent of whether which
Prolog system I use.
I tried the following:
:- multifile(term_expansion/2).
term_expansion((:- ensure_loaded(X)),
(:- atom_concat('<base>\\', X, Y),
include(Y))).
But the following query doesn't work:
:- ensure_loaded('suite.p').
The path calculation itself is not the issue of the question,
but the redefinition of a directive in GNU Prolog. There is
another directive that causes problems: meta_predicate/1. The
byte code crashes as follows:
Bye
A partial solution is:
ensure_loaded(File) :-
absolute_file_name(File, Path),
( predicate_property(_, prolog_file(Path)) ->
true
; consult(Path)
).
It assumes that the file defines at least one predicate but that's a sensible assumption. However, there's seems to be no way to override the native, non-functional, definition of the ensure_loaded/1 directive. A workaround would be to wrap the ensure_loaded/1 directive within an initialization/1 directive. For example:
:- initialization(ensure_loaded('suite.pl')).
Hence this being a partial solution as we're really defining an ensure_loaded/1 predicate, not a directive.
My current speculation is, that it is impossible with
the standard distribution of GNU Prolog 1.4.4. The
docu says:
The GNU Prolog compiler (section 4.4) automatically calls
expand_term/2 on each Term1 read in. However, in the current release,
only DCG transformation are done by the compiler (i.e.
term_expansion/2 cannot be used). To use term_expansion/2, it is
necessary to call expand_term/2 explicitly.
I also tried to inject some Prolog code for term_expansion/2
via the command line, but to no awail. Although the tool chain
has options such as -O, -L, -A that pass options to other tools.
There is not really an option that passes a Prolog text to the
pl2wam, in course of the execution of a consult/1 issued inside
the top-level.
At least this are my results so far.
Bye

How to override a user predicate with a module

Say I have a module named foo (defined in foo.pl). This module does term_expansion for instance:
:- module(foo,[term_expansion/2]).
term_expansion(A,A) :-
print A.
Of course the real code does something more complicated with the terms.
Now I want to import this library in a file, say test.pl:
:- use_module(foo).
fact(a).
When using swi-prolog however, I get the following error:
ERROR: Cannot import foo:term_expansion/2 into module user: name clash
How can I resove this error?
Term-expansion predicates are usually (they are not standard) declared as multifile (and possibly dynamic) predicates. In the specific case of SWI-Prolog, the term-expansion mechanism already defines and calls definitions for the term_expansion/2 predicate in the pseudo-module user. Thus, a possible solution would be to write instead:
:- module(foo).
:- multifile(user:term_expansion/2).
:- dynamic(user:term_expansion/2).
user:term_expansion(A,A) :-
print(A).
You should only need to load the definition of this module before loading files that you want to be term-expanded.
Regarding your follow up question about why the term_expansion/2 predicate is not declared multifile by default. I can give two different interpretations to your question. I'll address both. (1) Why do you need to repeat the multifile/1 directive? The ISO Prolog standard implies that a multifile predicate should be declared multifile in all files containing clauses for it (I say implies instead of specifies as the standard talks about "Prolog text" and not files). Actually, SWI-Prolog is quite liberal here but it's good practice to repeat the directives, moreover when other systems follow the standard more closely in this regard. (2) Why must the term-expansion predicates be declared multifile (and dynamic) in the first place? That depends on the implementation. E.g. in the Logtalk implementation of the term-expansion mechanism they are neither multifile nor dynamic.

Resources