Prolog term_expansion not working - prolog

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.

Related

Prolog Dynamic Predicates Basic Usage

with this knowledge base using https://swish.swi-prolog.org
:- dynamic happy/1.
go:-
assert(happy(mia)),
write(happy(mia)).
if I run go. I get
happy(mia)
true
If I just have
:- dynamic happy/1.
assert(happy(mia)).
and run happy(mia), I get false.
What fundamental concept am I missing please?
When you write:
assert(happy(mia)).
you are (re)defining the predicate assert/1, not calling it as in your definition of the go/0 predicate. Thus, happy(mia) is never added to the database. The query fails as the predicate happy/1 is know by the system (thanks to the dynamic/1 directive) but have no clauses.
Most Prolog systems prevent the redefinition of standard built-in predicates. But assert/1 is a legacy/deprecated predicate. That explains why SWI-Prolog doesn't complain about the redefinition. Always use the standard assertz/1 predicate instead of assert/1.

SWI-prolog semweb library processing of URI

Being new to prolog I am reading existing code (as well as trying to write some code). Having some prior background in semweb I started to play with it and see something that is confusing me. Example assertion:
?- rdf_assert(ex:bob, rdf:type, foaf:'Person').
I also did find the following in the documentation:
Remember: Internally, all resources are atoms. The transformations
above are realised at compile-time using rules for goal_expansion/2
provided by the rdf_db library
Am I correct in assuming that somehow the library is treating the three URIs as atoms? I thought that the compiler would treat this as module_name:predicate, but that does not seem to be the case. If that is true, could you please provide a simple example on how this could be done in prolog?
Thanks
Prolog is not a functional language. This implies 2+3 does not evaluate to 5 and is just a term that gets meaning from the predicate that processes it. Likewise, ex:bob is just a term that has no direct relations to modules or
predicates. Only predicates such call/1 will interpret this as "call bob in the module ex".
Next to that, (SWI-)Prolog (most Prolog's, but not all) have term expansion that allows you to rewrite the term that is read before it is handed to the compiler. That is used to rewrite the argument of rdf/3: each appearance of prefix:local is expanded to a full atom. You can check that by using listing/1 on predicates that call rdf/3 using the prefix notation.
See also rdf_meta

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.

adding a search Path in SWI prolog

In many Prolog systems it is easy to add a new search path for consulting file.
In Yap for example, the predicate I know it is add_to_path(NewPath).
Is there a way to do the same in SWI Prolog ?. My question is specifically about adding one path to the already existing paths, I am aware of the file_search_path/2 predicate for declaring directories, and the cd/1 predicate for changing the current directory, but I would like to know if there is an alternative method, like the one I found in Yap.
thanks in advance !
There are several mechanisms to this. The first one I met was in C-Prolog, which indeed used clauses for library_directory/1. The current SWI-Prolog mechanism is derived from Quintus and also used in SICStus. It generalises from the library_directory/1 approach
be treating expressions of the form <alias>(Path) as a search over the path-alias <alias>.
Paths for an alias are defined using the predicate file_search_path/2. Now, library is just an alias. Normally, libraries are added using a clause file_search_path(library, Dir).
This mechanism has proven to be pretty flexible. Of course, it would be nice if Prolog systems get more compatible here. I think todays YAP also supports the file_search_path system. (2016 Edit: It does indeed, see YAP Prolog User's Manual: Changing the Compiler’s Behavior)
In your .plrc/.yaprc/.sicstusrc/.swiplrc:
:- multifile(library_directory/1).
library_directory('/home/ulrich/lftp/Prolog-inedit').

Resources