How to export dynamically created predicate? - prolog

Consider the following code:
:- module(my_export, [create/2]).
create(Predicate, Id) :-
assertz(Predicate),
export(Id).
Assuming that the predicated and the identifier match, I'd expect the newly asserted predicate to be available outside the module. However, I get this output:
?- create(c(A,B) :- A > B, c/2).
true.
?- c(1,2).
Correct to: "my_export:c(1,2)"?
How come the predicate isn't exported? What is the correct way to do this?

You have to import module by using use_module/1.
For example, if this is sample_module.pl:
:- module(my_export, [create/2]).
create(Predicate, Id) :-
assertz(Predicate),
export(Id).
Then this input and output is true (observe closely what's going on):
?- create(tmp(A,B) :- A > B, tmp/2).
ERROR: toplevel: Undefined procedure: create/2 (DWIM could not correct goal)
?- consult('c:\\Prolog\\pl\\bin\\sample_module.pl').
% c:\Prolog\pl\bin\sample_module.pl compiled into my_export 0.00 sec, 2 clauses
true.
?- create(tmp(A,B) :- A > B, tmp/2).
true.
?- tmp(1,2).
Correct to: "my_export:tmp(1,2)"? yes
false.
?- use_module('c:\\Prolog\\pl\\bin\\sample_module.pl').
true.
?- tmp(1,2).
false.
?- tmp(5,4).
true.
Now, when you "compile buffer" in SWI-Prolog what really happens is consult/1. You need to import your module manually.

Your code work as-is, as long as the module is initially imported, as Grzegorz explained. For example:
?- [user].
:- module(my_export, [create/2]).
|:
|: create(Predicate, Id) :-
|: assertz(Predicate),
|: export(Id).
|: % user://1 compiled into my_export 0.00 sec, 2 clauses
true.
?- module_property(my_export, P).
P = class(user) ;
P = file('user://1') ;
P = line_count(10) ;
P = exports([create/2]) ;
false.
?- my_export:create(c(A,B) :- A > B, c/2).
true.
?- module_property(my_export, P).
P = class(user) ;
P = file('user://1') ;
P = line_count(10) ;
P = exports([c/2, create/2]) ;
false.
?- create(tmp(A,B) :- A > B, tmp/2).
true.
?- module_property(my_export, P).
P = class(user) ;
P = file('user://1') ;
P = line_count(10) ;
P = exports([tmp/2, c/2, create/2]) ;
false.
Note, however, that export/1 is usually a directive, not a predicate. There might be portability issues to other Prolog dialects supporting a module system.

Related

Constraint Handling Rules in SWI Prolog: The `neq` constraint doesn't work

I am learning Constraint Handling Rules (CHR) in swi-prolog.
I started with the tutorial from Tom Schrijvers' Constraint Handling Rules A Tutorial for (Prolog) Programmers.
In p.286, the author gave an example to implement Inequality constraint.
:- use_module(library(chr)).
:- chr_constraint neq/2.
neq(X,X) <=> fail.
neq(X,Y) <=> X \= Y | true.
But it does not work as expected in swi-prolog.
For example, in swi-prolog
?- neq(A,B).
true.
?- neq(A,B), A = B.
A = $VAR(B).
but it should be
?- neq(A,B).
neq(A,B).
?- neq(A,B), A = B.
false.
How can I get the same result as in the slide?
My swi-prolog version (threaded, 64 bits, version 8.2.4) on windows.
Thanks.
You may use ?=/2 for your second clause:
:- use_module(library(chr)).
:- chr_constraint neq/2.
neq(X,X) <=> fail.
neq(X,Y) <=> ?=(X,Y) | true.
Sample runs:
?- neq(a,a).
false.
?- neq(a,b).
true.
?- neq(A,B).
neq(A, B).
?- neq(A,B), A = f(C), B = f(D).
A = f(C),
B = f(D),
neq(f(C), f(D)).
?- neq(A,B), A = [1,X], B=[].
A = [1, X],
B = [].
Here is a temporary workaround for neq:
:- use_module(library(chr)).
:- chr_constraint neq/2.
neq(X,X) <=> fail.
neq(X,Y) <=> ground(X), ground(Y) | true.
It can pass all the tests in the slide:
?- neq(a,a).
false.
?- neq(a,b).
true.
?- neq(A,B).
neq($VAR(A),$VAR(B)).
?- neq(A,B), A = B.
false.
?- neq(A,B), A = a, B = a.
false.
?- neq(A,B), A = a, B = b.
A = a,
B = b.
?- neq(A,B), A = f(C), B = f(D).
A = f($VAR(C)),
B = f($VAR(D)),
neq(f($VAR(C)),f($VAR(D))).
%% And some other tests which not in the slide.
?- neq([1,2,3], [1,2,X]).
neq([1,2,3],[1,2,$VAR(X)]).
?- neq([1,2,3], [1,2,X]), X=3.
false.
?- neq([1,2,3], [1,2,X]), X=4.
X = 4.
?- neq([1,2,3], X).
neq([1,2,3],$VAR(X)).
?- neq([1,2,3], X), X=[1,2,3].
false.
?- neq([1,2,3], X), X=[1,2,Y].
X = [1,2,$VAR(Y)],
neq([1,2,3],[1,2,$VAR(Y)]).
It seems that the current CHR implementation inhibits binding variables that appear at the head in guards (see Check guard bindings yourself), even if these bindings could roll back via \+. Note that X \= Y equivalents to \+ X = Y. Also, the unification predicate = in guards seems only comparing with variables' identifier instead of unifying them.
The drawback of this workaround is that, for example,
?- neq(A,B), A = [1,X], B=[].
A = [1,$VAR(X)],
B = [],
neq([1,$VAR(X)],[]).
Since A is not ground, the second rule doesn't fire, but we know that A and B cannot be equal, i.e. neq([1,$VAR(X)],[]) should have been removed.
Anyway, it's just a temporary workaround. If someone has a better solution or explanation, I could delete this answer.

Prolog membership predicate without dif or when

The following prolog logic
memberd(X, [X|_T]).
memberd(X, [Y| T]) :- dif(X,Y), memberd(X, T).
will produce
?- memberd(a, [a, b, a]).
true
?- memberd(X, [a, b, a]).
X = a ;
X = b ;
false.
?- memberd(X, [a, b, a, c, a, d, b]).
X = a ;
X = b ;
X = c ;
X = d ;
false.
is there prolog logic that can be used to produce the same result without using when() or dif() function or anything from a loaded prolog library. Just using pure logic?
To answer your question literally, just use:
?- setof(t, member(X, [a,b,a]), _).
X = a
; X = b.
However, some answers will be suboptimal:
?- setof(t,member(a,[a,X]),_).
true
; X = a. % redundant
... whereas memberd/2 answers in perfection:
?- memberd(a,[a,X]).
true
; false.
In fact, if you use library(reif) with
memberd(E, [X|Xs]) :-
if_(E = X, true, memberd(E, Xs) ).
you get the best answer possible:
?- memberd(a,[a,X]).
true.

Expanding Prolog clauses with forall/2

I'm using clause/2 to transform some Prolog clauses in a compiler. I need to replace the head of each clause with its body, but clause/2 sometimes doesn't expand the clause in the way that it was originally written.
Here, clause/2 expands demo(A,B) to \+ (call(A),\+call(B)), instead of expanding its original definition:
:- use_module(prolog_to_minizinc).
:- initialization(main).
main :-
writeln(forall(A,B)),
clause(demo(A,B),Clause),
writeln(Clause).
demo(A,B) :-
forall(A,B).
Is there another way to expand clauses, without modifying clauses that include forall/2?
The unwanted expansion of the forall/2 goal is due to SWI-Prolog loading library(apply_macros) at startup. This library provides the expansion code for forall/2 and other predicates. Finding how library(apply_macros) is loaded is not trivial as setting the verbose_autoload flag to true in the ~/.config/swi-prolog/init.pl file doesn't print all libraries that are being auto-loaded at startup. On my laptop, using the current devel git version of SWI-Prolog (8.1.21-82-ge6e1d5376-DIRTY):
?- current_module(apply_macros).
true.
?- module_property(apply_macros, P).
P = class(library) ;
P = file('/Users/pmoura/lib/swipl/library/apply_macros.pl') ;
P = line_count(36) ;
P = exports([expand_phrase/2, expand_phrase/4]) .
?- source_file_property('/Users/pmoura/lib/swipl/library/apply_macros.pl', P).
P = modified(1547476368.0) ;
P = source(file) ;
P = module(apply_macros) ;
P = load_context(nb_set, '/Users/pmoura/lib/swipl/library/nb_set.pl':45, [imports([])]) ;
P = load_count(1) ;
P = number_of_clauses(52).
?- source_file_property('/Users/pmoura/lib/swipl/library/nb_set.pl', P).
P = modified(1547476368.0) ;
P = source(file) ;
P = module(nb_set) ;
P = load_context(solution_sequences, '/Users/pmoura/lib/swipl/library/solution_sequences.pl':46, []) ;
P = load_count(1) ;
P = number_of_clauses(13).
?- source_file_property('/Users/pmoura/lib/swipl/library/solution_sequences.pl', P).
P = modified(1574086719.0) ;
P = source(file) ;
P = module(solution_sequences) ;
P = load_context(editline, '/Users/pmoura/lib/swipl/library/editline.pl':59, []) ;
P = load_count(1) ;
P = number_of_clauses(49).
The file editline.pl provides the default convenient command-line history and other services. But if you switch to readline by adding to your ~/.config/swi-prolog/init.pl file the directive:
:- set_prolog_flag(readline, readline).
Then you get:
?- [user].
|: a(A,B) :- forall(A,B).
|: % user://1 compiled 0.00 sec, 1 clauses
true.
?- listing(a/2).
% autoloading user:listing/1 from /Users/pmoura/lib/swipl/library/listing
a(A, B) :-
forall(A, B).
true.
This is a poor workaround but it may help you.

SWI Prolog Database

is there a way I can query a SWI Prolog database to check if it doesn't contain an element?
I have tried using "not" but doesn't seem to work with this version of Prolog.
maybe you're looking for clause/2. A dummy session sample
1 ?- [user].
|: a(1).
|: a(2).
|: a(X) :- b(X).
|: b(3).
|: b(4).
% user://1 compiled 0.03 sec, 6 clauses
true.
2 ?- clause(a(X),Body).
X = 1,
Body = true ;
X = 2,
Body = true ;
Body = b(X).
3 ?- clause(b(X),Body).
X = 3,
Body = true ;
X = 4,
Body = true.
4 ?- clause(c(X),Body).
false.
you can see that c/1 is not defined...
Anyway, SWi-Prolog database is a complex beast, and it offers much more control about its contents.

Prolog: How to check if a predicate exists?

How can I check if a predicate exists in a Prolog program? That would be an exists/1, like:
?- exists(some_predicate).
false.
?- assert(some_predicate).
true.
?- exists(some_predicate).
true.
You can use current_predicate/1, current_predicate/2 or predicate_property/2 (for the last you will probably need functor/3):
?- current_predicate(a/1).
false.
?- functor(A,a,1),predicate_property(A,visible).
false.
?- functor(A,a,1),current_predicate(_,A).
false.
?- assert(a(42)).
true.
?- current_predicate(a/1).
true.
?- functor(A,a,1),predicate_property(A,visible).
A = a(_G136).
?- functor(A,a,1),current_predicate(_,A).
A = a(_G122).
current_predicate/2 and predicate_property/2 (with visible) succeeds if the predicate can be autoloaded while currrent_predicate/1 fails
the 'old fashioned way', but accepted in ISO, is clause/2. You could encounter it while reusing/browsing some of the older examples.
example:
?- [user].
|: app([], Y, Y).
|: app([X|Xs], Y, [X|Zs]) :- app(Xs, Y, Zs).
|: % user://1 compiled 0,15 sec, 17 clauses
true.
?- clause(app(X,Y,Z),Body).
X = [],
Y = Z,
Body = true ;
X = [_G338|_G339],
Z = [_G338|_G342],
Body = app(_G339, Y, _G342).

Resources