Arguments are not sufficiently instantiated in clause/2 - prolog

i'm trying to write a simple meta-interpreter for the unification in prolog, this is what i got so far
unify(A,B):-var(A),A=B.
unify(A,B):-nonvar(A),var(B),B=A.
unify(A,B):-compound(A),compound(B),A=..[F|ArgsA],B=..[F|ArgsB],unify_args(ArgsA,ArgsB).
unify_args([A|TA],[B|TB]):-unify(A,B),unify_args(TA,TB).
unify_args([],[]).
meta(true).
meta((A,B)):- meta(A),meta(B).
meta(C):-clause(H,B), unify(H,C), meta(B).
the problem that i'm getting is that when i try to unify two variables e.g
meta((A,B)).
i get the correct result
A = B, B = true .
but when i try to unify anything else for example
meta((a,a)).
or even a compund i get the following error:
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [12] clause(_4306,_4308)
ERROR: [11] meta(a) at path_redacted/unify1.pl:22
ERROR: [10] meta((a,a)) at path_redacted/unify1.pl:21
ERROR: [9] <user>
i can't understand why clause/2 would need instantiated argouments in this particular case, or maybe i'm missing something else?
Thank you for any help

As Will Ness pointed out in a comment, clause/2 requires the Head to be instantiated.
As written, your meta-interpreter tries to enumerate all clauses of all predicates in the program to find ones that unify with the goal term C. You will have to restrict this to only enumerating clauses that match C. One way to do this would be to call clause(C, Body) directly. I guess you want to avoid this, since this would cheat by doing the unification for you.
The other way is to copy C's functor, but not its arguments. You can use this copy to look up clauses for the predicate of interest, but you will still be able to do the unification yourself.
Here is how you can do such a "skeleton" copy:
?- C = f(x, y), functor(C, Functor, Arity), functor(Skeleton, Functor, Arity).
C = f(x, y),
Functor = f,
Arity = 2,
Skeleton = f(_70, _72).
In the context of your meta-interpreter, something like this gets you closer to what you want:
meta(Goal) :-
functor(Goal, Functor, Arity),
functor(Head, Functor, Arity),
clause(Head, Body),
unify(Head, Goal),
meta(Body).
For example, using this example program:
f(x).
g(y).
fg(X, Y) :-
f(X),
g(Y).
We get:
?- meta(fg(X, Y)).
X = x,
Y = y ;
ERROR: No permission to access private_procedure `true/0'
ERROR: In:
ERROR: [12] clause(true,_2750)
...
The solution is found correctly, but backtracking for further answers tries to access a clause for true. This is not allowed by SWI-Prolog. You will have to be more careful about making the clauses of the meta-interpreter mutually exclusive. You will probably need to place cuts.

Related

SWI Prolog list subtract gives error: Out of local stack

I'm running some Prolog rule which uses the subtract function and in the stack trace, I found the source of error to be this:
lists:subtract([b, d | _], [b, d] , [r]) ? creep
ERROR: Out of local stack
The original call was:
member(b, X), member(d, X), subtract(X, [b, d], [r]).
and the expected output is [b, d, r].
I'm new to Prolog and unable to understand the source of error and how to fix it. Please help.
unable to understand the source of error and how to fix it.
Just take your query and look at the first two goals alone:
?- member(b, X), member(d, X).
X = [b,d|_A]
; X = [b,_A,d|_B]
; X = [b,_A,_B,d|_C]
; X = [b,_A,_B,_C,d|_D]
; X = [b,_A,_B,_C,_D,d|_E]
; ... .
Just these two goals produce already infinitely many answers. So no matter what follows, your query will never terminate. By chance, you may happen to get a solution, but more often than not you will end in some loop.
So first of all you need to fix this somehow.
Then consider the meaning of subtract/3 in SWI:
?- subtract([b,d,r], [b,d], [r]).
true.
?- subtract([b,d,X], [b,d], [r]).
false. % ?? why not X = r?
From this alone you can see that subtract/3 is not a relation. So you cannot use it as a relation like, say, append/3.
To fix this and keep as close to your original query, use library(reif) and library(lambda):
?- S1=[b,d,X], S2 = [b,d], tpartition(S2+\E^memberd_t(E,S2),S1,_,[r]).
S1 = [b,d,r], X = r, S2 = [b,d].
From SWI Prolog manual :
The library(lists) contains a number of old predicates for manipulating sets represented as unordered lists, notably intersection/3, union/3, subset/2 and subtract/3. These predicates all use memberchk/2 to find equivalent elements. As a result these are not logical while unification can easily lead to dubious results.
You are having this problem because subtract isn't pure and needs it's first two Arguments to be instantiated hence the + sign in it's documentation .
subtract(+Set, +Delete, -Result)
you can instead use union/3
union(+Set1, +Set2, -Set3)
you can know more about other mode indicators in here.

Is there a Prolog name for atom/1 or stream/1 etc (SWI-Prolog)

Just made a funny observation. SWI-Prolog allows other things than
atom as a functor in a compound. For example it allows me to do:
/* atom as functor */
?- Y =.. [foo, bar].
Y = foo(bar).
/* stream as functor */
?- current_input(X), Y =.. [X, bar].
X = <stream>(0000000069066420),
Y = <stream>(0000000069066420)(bar).
I wonder whether there is a name for what is allowed as a functor,
i.e atom or stream etc.. . The error message by SWI-Prolog doesn't
tell me what is the name, it says it expects an atom:
?- Y =.. [1, bar].
ERROR: Type error: `atom' expected, found `1' (an integer)
But as can be seen a stream etc.. , which is accepted, is not an atom:
?- current_input(X), atom(X).
false.
What is the umbrella type for what SWI-Prolog accepts as functor?
P.S. My guess why this is allowed: It is for example used for Dicts,
dicts are compounds with a special functor C'dict'.
Edit 10.09.2021:
I first thought its simple/1. But simple/1 is reserved
for atom or var, according to this answer:
What is the meaning of predicate "simple/1" in Prolog (SWI-Prolog)
In SWI-Prolog, blobs (binary large objects) are used to store arbitrary binary data, including atoms, images, and stream handles. Particularly, a blob represening a stream handle is a unique symbol which has no syntactical representation (although it is outputted as <stream>(hex-number)).
The built-in predicate blob/2 can be used to get the type of a blob:
?- X = foo, blob(X,Y).
X = foo,
Y = text.
?- current_input(X), blob(X,Y).
X = <stream>(0000000069057160),
Y = stream.
Thus, I think the type accepted as functor in SWI-Prolog is blob.
In Dogelog Runtime we recently introduced a new type tester called symbol/1. One can imagine that it is bootstrapped from blob/2 as follows:
symbol(X) :- blob(X, _).
Dogelog Runtime does also accept symbols as functors, similar like SWI-Prolog. This is used to inline disjunction and if-then-else, and could have further optimization use cases. Functors are not only restricted to atoms, they can be atoms or references:
/* Dogelog Runtime, 0.9.6 */
?- current_input(X), atom(X).
fail.
?- current_input(X), Y =.. [X, bar].
X = [object Object], Y = [object Object](bar).
But I am currently thinking about extending (=..)/2 even more. Namely to allow a compound as functor. What should a compound as functor do? Very simple:
/* Expected Result */
?- X =.. [foo(bar), baz].
X = foo(bar, baz)
So (=..)/2 would add the arguments to the given compound. This further extension of (=..)/2 doesn't need a new data type in the compound functor, but rather changes its behaviour.
It would have a couple of use cases:
Old Higher Order:
Bootstrapping apply/2 would be as easy as:
apply(X,L) :- G =.. [X|L], G.
New Higher Order:
Bottstrapping call/n would be as easy as:
call(X,Y) :- G =.. [X,Y], G.
call(X,Y,Z) :- G =.. [X,Y,Z], G.
call(X,Y,Z,T) :- G =.. [X,Y,Z,T], G.
Etc..
DCG Expansion:
Expanding a non-terminal by an input and output list would be only a matter of calling (=..)/2. Here is an example:
?- G =.. [np(X),I,O].
G = np(X,I,O).

prolog unary numbers - evaluating expression

I am trying to understand Prolog and I came up to following situation. I have defined natural numbers (unary) in following way:
n(0).
n(s(X)) :- nat(X).
Which means that 0 is 0, s(0) is 1, s(s(0)) is 2 etc...
Then I defined predicate add:
add(0, Y, Y) :- nat(Y).
add(s(X), Y, s(Z)) :-
add(X, Y, Z).
Which adds two unary numbers and result stores to Z.
Now I have following predicate "test" what demonstrates my problem:
test(s(0),0).
Then in interpret I type:
add(s(0),0,R). %result: R = s(0), which is correct
Then i try:
test(add(s(0),0,R), 0).
So the first argument should result in R = s(0), second argument is zero, so the whole expression should be evaluated as true, but prolog says false. I guess that it has something to do with the point, that the add(s(0),0,R) inside the "test" predicate does not evaluate the way I think. Could anyone please explain this to me or eventually provide some link that describes this behaviour? Thanks for any help!
Cheers.
No, prolog does not work the way you assume it to.
When you ask
?- test(add(s(0),0,R), 0).
prolog tries to find a matching clause. However, there is no matching clause in your database, since s(0) does not match add(s(0),0,R). Two structures can only match if the have the same functor.
s(0) has the functor s while add(s(0),0,R) has the functor add.

DRY arithmetic expression evaluation in Prolog

I wanted to write evaluating predicate in Prolog for arithmetics and I found this:
eval(A+B,CV):-eval(A,AV),eval(B,BV),CV is AV+BV.
eval(A-B,CV):-eval(A,AV),eval(B,BV),CV is AV-BV.
eval(A*B,CV):-eval(A,AV),eval(B,BV),CV is AV*BV.
eval(Num,Num):-number(Num).
Which is great but not very DRY.
I've also found this:
:- op(100,fy,neg), op(200,yfx,and), op(300,yfx,or).
positive(Formula) :-
atom(Formula).
positive(Formula) :-
Formula =.. [_,Left,Right],
positive(Left),
positive(Right).
?- positive((p or q) and (q or r)).
Yes
?- positive(p and (neg q or r)).
No
Operator is here matched with _ and arguments are matched with Left and Right.
So I came up with this:
eval(Formula, Value) :-
Formula =.. [Op, L, R], Value is Op(L,R).
It would be DRY as hell if only it worked but it gives Syntax error: Operator expected instead.
Is there a way in Prolog to apply operator to arguments in such a case?
Your almost DRY solution does not work for several reasons:
Formula =.. [Op, L, R] refers to binary operators only. You certainly want to refer to numbers too.
The arguments L and R are not considered at all.
Op(L,R) is not valid Prolog syntax.
on the plus side, your attempt produces a clean instantiation error for a variable, whereas positive/1 would fail and eval/2 loops which is at least better than failing.
Since your operators are practically identical to those used by (is)/2 you might want to check first and only then reuse (is)/2.
eval2(E, R) :-
isexpr(E),
R is E.
isexpr(BinOp) :-
BinOp =.. [F,L,R],
admissibleop(F),
isexpr(L),
isexpr(R).
isexpr(N) :-
number(N).
admissibleop(*).
admissibleop(+).
% admissibleop(/).
admissibleop(-).
Note that number/1 fails for a variable - which leads to many erroneous programs. A safe alternative would be
t_number(N) :-
functor(N,_,0),
number(N).

prolog instantiation error with =:= operator

I'm writing a function called subseq which checks if one list is a subsequence of another.
subseq([],[]).
subseq([],[Y|Ys]).
subseq([X|Xs],[Y|Ys]) :- X=:=Y, subseq(Xs,Ys).
subseq([X|Xs],[Y|Ys]) :- X=\=Y, subseq([X|Xs],Ys).
When I try subseq(X,[1,2]) I get:
X = [] ? ;
uncaught exception: error(instantiation_error,(=:=)/2)
Why is this happening? My guess is that [] is being operated on by =:=, but how do I check for/prevent this error?
You use =:= and =\= in the wrong context here. Those two operators should be used when you have two expressions at hand and want to evaluate and compare them. In your test, because X is not known beforehand, Prolog couldn't evaluate X and compare with Y. More information about =:= and =\= could be found here: Prolog Operator =:=.
In your code you only need unification for atoms so one possible fix could be:
subseq([],[]).
subseq([],[_|_]).
subseq([X|Xs],[Y|Ys]) :- X=Y, subseq(Xs,Ys).
subseq([X|Xs],[Y|Ys]) :- X\=Y, subseq([X|Xs],Ys).

Resources