Related
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.
I'm trying to solve a prolog question. I'm trying to print the players who is playing in Arsenal. I couldn't solve the problem.
player(rick,arsenal)
player(tom,dortmund)
player(paul,bayern)
player(tim,liverpool)
player(john,arsenal)
player(andrew,arsenal)
the output has to be:
?- sameteam(????)
X= [rick,john,andrew]
First, your facts need to be terminated with a "." to be correct Prolog syntax
player(rick,arsenal).
player(tom,dortmund).
player(paul,bayern).
player(tim,liverpool).
player(john,arsenal).
player(andrew,arsenal).
In "relational database fashion", let's first collect the ground atoms (in the sense of "logic atoms", i.e. "facts") that match the condition "plays at arsenal".
Fire up your preferred Prolog, and then:
?- [user].
|: player(rick,arsenal).
|: player(tom,dortmund).
|: player(paul,bayern).
|: player(tim,liverpool).
|: player(john,arsenal).
|: player(andrew,arsenal).
|: ^D% user://2 compiled 0.00 sec, 6 clauses
true.
?- player(Who,arsenal).
Who = rick ;
Who = john ;
Who = andrew.
Now we just need to "collect them into a list" and we can do that easily using setof/3:
?- setof(Who,player(Who,arsenal),Players).
Players = [andrew, john, rick].
This is all bog-standard "asking the database" work.
We can pack the above into a predicate for easier usage:
?- [user].
|: sameteam(Players) :- setof(Who,player(Who,arsenal),Players).
|: ^D% user://3 compiled 0.00 sec, 1 clauses
true.
?- sameteam(Players).
Players = [andrew, john, rick].
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.
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).
I am trying to perform a sum operation on every result of :
combination(0,_,[]).
combination(K,L,[X|Xs]) :-
K > 0,
el(X,L,R),
K1 is K-1,
combination(K1,R,Xs).
el(X,[X|L],L).
el(X,[_|L],R) :- el(X,L,R).
For example, the user will enter is_sum_equal_10 ([1,2,3,4,5,6,7]) and the result will be true if the sum of any of the permutations equals 10.
I am struggling with putting it all together, can someone please help me define the is_sum_equal_10 rule that uses the combination rule for each permutation?
OK, well it's pretty easy to write really, you just need a rule to say if a particular combination sums to 10, and then another extra one to count up through the different sizes of combination lists (which is required due to the way you wrote combination with the K that you need to decrease as you check the rule).
1 ?- [user].
|: combination(0,_,[]).
|: combination(K,L,[X|Xs]) :- K > 0,
|: el(X,L,R), K1 is K-1, combination(K1,R,Xs).
|: el(X,[X|L],L).
|: el(X,[_|L],R) :- el(X,L,R).
|:
|: totals_10([],10).
|: totals_10([X|Xs],T) :- N is T+X, totals_10(Xs,N).
|:
|: is_comb_sum_equal_10(Numbers,_,R) :- combination(R,Numbers,C), totals_10(C,0).
|: is_comb_sum_equal_10(Numbers,N,R) :- Rnext is R+1, Rnext =< N,
|: is_comb_sum_equal_10(Numbers,N,Rnext).
|:
|: is_sum_equal_10(Numbers) :- length(Numbers,N), is_comb_sum_equal_10(Numbers,N,0).
|:
% user://1 compiled 0.13 sec, 1,824 bytes
true.
2 ?- is_sum_equal_10([2,3,5]).
true .
3 ?- is_sum_equal_10([2,235,124,3,3347,5,2373]).
true .
4 ?- is_sum_equal_10([2,235,124,3,3347,6,2373]).
false.
5 ?- is_sum_equal_10([1,1,1,1,1,-1,1,1,1,1,12]).
false.
6 ?- is_sum_equal_10([1,1,1,1,1,-1,1,1,1,1,11]).
true ;
false.
Since you don't care about the actual list or how big it is in the is_sum_equal_10 thing, you can just sum the combinations as you go along, and even better, check the sum is correct as a rule for the base case. I think it's a bit neater if you subtract from the desired total to get to 0 at the base rather than adding up and checking at the end against the value you want. This gives you a very simple single ruleset to look for a certain sum.
7 ?- [user].
|: is_subset_sum(0,[]).
|: is_subset_sum(N,[_|Xs]) :- is_subset_sum(N,Xs).
|: is_subset_sum(N,[X|Xs]) :- R is N-X, is_subset_sum(R,Xs).
|:
% user://2 compiled 0.03 sec, 540 bytes
true.
8 ?- is_subset_sum(10,[3,5,6]).
false.
9 ?- is_subset_sum(10,[123,4,1,77,3,2,34]).
true .
10 ?- is_subset_sum(11,[0,2,4,6,8,10,12,14,16,18,20,22]).
false.
This approach is of course both much easier to understand, and a lot more efficient.