Prolog read compound term and treating it like an expression - prolog

The following code isn't working
:- arithmetic_function(i/2).
i(X,Y,Z) :-
Z is X+Y.
calcola :-
write('Give me an expression'),nl,
read(ESP),
Z is ESP,nl,nl,
write(Z).
but the following is
:- arithmetic_function(i/2).
i(X,Y,Z) :-
Z is X+Y.
calcola :-
write('Give me an expression'),nl,
Z is 4 i 2,nl,nl,
write(Z).
Why is that? Seems like the "read" function isn't working properly

from SWI-Prolog mailing list ([SWIPL] Ann: SWI-Prolog 5.11.23, 23 Jun):
MODIFIED: User-defined arithmetic functions have been removed from
the kernel. There is a new library(arithmetic) that emulates the
old behaviour PARTIALLY. Notably:
This library must be loaded before arithmetic_function/1 is
used.
It only covers arithmetic functions that are visible as an argument
to is/2, >/2, etc. at compile-time.
A new predicate arithmetic_expression_value/2 can be used to
evaluate expressions with embedded user arithmetic that become
instantiated at runtime.

Well as a lead, when I test it with is/2 it fails but when I use arithmetic_expression_value/2 it succeeds :
:- arithmetic_function(i/2).
:- op(20, xfx, i).
i(X, Y, Z) :-
Z is X + Y.
calcola :-
writeln('Give me an expression'),
read(ESP),
arithmetic_expression_value(ESP, Z), nl,
write(Z).
For #gusbro, it works out of the box. I'm using windows swi-pl here, for the record !
Others may have clues about why it fails for us !

Related

How to restrict values of an argument in Prolog using a series of facts?

I want to restrict the query property(X, use, Y) to values of Y in the list [a,b,c].
c/1 is true for only those values of Y.
I thought the following would work, but it doesn't.
c(a).
c(b).
c(c).
property(X, use, Y).
c(Y).
The following statements yield only false.
person(1).
property(1, use, _).
I'm using Problog, but I'm not using any Problog functions here, so I think I am misunderstanding something about unification.
I thought c(Y) would generate the list and Y would be unified across the facts.
Update
This does seem to be an Problog-specific issue as the following illustrates.
substance(methadone).
substance(heroin).
P::property(X,use,nicotine) :- %doesn't work
property(X,use,Z),
substance(Z),
P is 0.8.
property(X,use,nicotine) :- %works
property(X,use,Z),
substance(Z).
person(1).
substance(Y).
property(1, use, Y).
You can write:
property(_X, use, Y) :-
c(Y).

Proper unify_with_occurs_check/2 in SWI-Prolog?

Got this strange behaviour. I was running these test cases:
s1 :-
Q=[[lambda,symbol(_3026),[cons,[quote,_3434],
[quote,_3514]]],[quote,_3206]],
P=[_3434|_3514],
freeze(_3434, (write(foo), nl)),
unify_with_occurs_check(P, Q).
s2 :-
Q=[[lambda,symbol(_3026),[cons,[quote,_3434],
[quote,_3514]]],[quote,_3206]],
P=[_3434|_3514],
freeze(_3434, (write(foo), nl)),
freeze(_3514, (write(bar), nl)),
unify_with_occurs_check(P, Q).
Now I get these results, where the outcome of s2 is wrong. The outcome is wrong in two respects, first _3434 gets triggered and second unify_with_occurs_check succeeds:
SWI-Prolog (threaded, 64 bits, version 8.3.16)
?- s1.
false.
?- s2.
foo
bar
true.
That _3434 shouldn't get triggered follows from 7.3.2 Herband Algorithm in ISO core standard. According to clause 7.3.2 f) 1) an instantiation of variable X to a term t is only propagated when it X does not occur in t.
That the unification should fail follows from clause 7.3.2 g). So it seems in SWI-Prolog, attributed variables in various incarnations such as freeze/2, dif/2, etc… seem to interfer with unify_with_occurs_check.
Any workaround?
Edit 06.02.2021:
The bug has been fixed in SWI-Prolog 8.3.17 (devel) and
was backported to SWI-Prolog 8.2.4 (stable) as well.
Here is another somewhat simpler workaround:
unify(X,X) :-
acyclic_term(X).
Certainly, this only works as expected if the two arguments are finite from the very start, but at least it does not loop in this case.
One way out could be to roll your own unify_with_occurs_check/2. We can write it in Prolog itself, as was done in the past, for Prolog systems that did not have unify_with_occurs_check/2:
R.A.O'Keefe, 15 September 1984
http://www.picat-lang.org/bprolog/publib/metutl.html
Here is an alternative take that uses (=..)/2 and term_variables/2:
unify(X, Y) :- var(X), var(Y), !, X = Y.
unify(X, Y) :- var(X), !, notin(X, Y), X = Y.
unify(X, Y) :- var(Y), !, notin(Y, X), X = Y.
unify(X, Y) :- functor(X, F, A), functor(Y, G, B),
F/A = G/B,
X =.. [_|L],
Y =.. [_|R],
maplist(unify, L, R).
notin(X, Y) :-
term_variables(Y, L),
maplist(\==(X), L).
I now get the expected result:
?- s1.
false.
?- s2.
false.

Expanding Prolog clauses without parameters

I am writing a program that transforms other programs by expanding predicates. I usually do this using clause/2, but it doesn't always expand a predicate if it has no parameters:
:- set_prolog_flag('double_quotes','chars').
:- initialization(main).
main :- clause(thing,C),writeln(C).
% this prints "true" instead of "A = 1"
thing :- A = 1.
Is it possible to expand predicates that have no parameters?
Some general remark: Note that this code is highly specific to SWI. In other systems which are ISO conforming you can only access definitions via clause/2, if that predicate happens to be dynamic.
For SWI, say listing. to see what is happening.
?- assert(( thing :- A = 1 )).
true.
?- listing(thing).
:- dynamic thing/0.
thing.
true.
?- assert(( thing :- p(A) = p(1) )).
true.
?- assert(( thing(X) :- Y = 2 )).
true.
?- listing(thing).
:- dynamic thing/0.
thing.
thing :-
p(_)=p(1).
:- dynamic thing/1.
thing(_).
true.
It all looks like some tiny source level optimization.

Prolog addition on wrapped values

I wrote a test program with bindings (facts) between atoms and numbers.
bind(a, 3).
bind(b, 4).
bind(c, 5).
As part of a toy interpreter, I want to be able to perform additions on these atoms using Prolog's native arithmetic operators. For instance, I want to be able to run this query:
% val(X) is the value bound to X
?- X is val(a) + val(b).
X = 7.
However, I'm struggling to find a way to allow this addition. My first approach would have been this one:
% val(X, Y): Y is the value bound to X
val(X, Y) :- bind(X, Y).
% Make val an arithmetic function
:- arithmetic_function(val/1).
However, arithmetic_function/1 is no longer part of Prolog (or at least SWI-Prolog says it's deprecated), so I can't use it. Then I believed the best solution would be to overload the + operator to take this into account:
% val(X, Y): Y is the value bound to X
val(val(X), Y) :- bind(X, Y).
% Overload the + operator
+(val(_X, XVal), val(_Y, YVal)) :- XVal + YVal.
But here I've got my syntax all messed up because I don't really know how to overload a native arithmetic operation. When I type in the sample query from before, SWI-Prolog says ERROR: Arithmetic: ``val(a)' is not a function.
Would you have hints about a possible solution or a better approach or something I missed?
From the docs, I tought you should use function_expansion/3.
But I'm unable to get it to work, instead, goal_expansion could do, but isn't very attractive... for instance, if you save the following definitions in a file bind.pl (just to say)
:- module(bind, [test/0]).
:- dynamic bind/2.
bind(a, 3).
bind(b, 4).
bind(c, 5).
% :- multifile user:goal_expansion/2.
user:goal_expansion(val(X), Y) :- bind(X, Y).
user:goal_expansion(X is Y, X is Z) :- expand_goal(Y, Z).
user:goal_expansion(X + Y, U + V) :- expand_goal(X, U), expand_goal(Y, V).
test :-
X is val(a) + val(b), writeln(X).
and consult it, you can run your test:
?- test.
7
edit
after Paulo suggestion, here is an enhanced solution, that should work for every binary expression.
user:goal_expansion(X is Y, X is Z) :- expr_bind(Y, Z).
expr_bind(val(A), V) :- !, bind(A, V).
expr_bind(X, Y) :-
X =.. [F, L, R], % get operator F and Left,Right expressions
expr_bind(L, S), % bind Left expression
expr_bind(R, T), % bind Right expression
Y =.. [F, S, T]. % pack bound expressions back with same operator
expr_bind(X, X). % oops, I forgot... this clause allows numbers and variables
having defined user as target module for goal_expansion, it works on the CLI:
?- R is val(a)*val(b)-val(c).
R = 7.
edit
now, let's generalize to some other arithmetic operators, using the same skeleton expr_bind uses for binary expressions:
user:goal_expansion(X, Y) :-
X =.. [F,L,R], memberchk(F, [is, =<, <, =:=, >, >=]),
expr_bind(L, S),
expr_bind(R, T),
Y =.. [F, S, T].
and unary operators (I cannot recall no one apart minus, so I show a simpler way than (=..)/2):
...
expr_bind(-X, -Y) :- expr_bind(X, Y).
expr_bind(X, X).
Now we get
?- -val(a)*2 < val(b)-val(c).
true.
One way to do it is using Logtalk parametric objects (Logtalk runs on SWI-Prolog and 11 other Prolog systems; this makes this solution highly portable). The idea is to define each arithmetic operation as a parametric object that understands an eval/1 message. First we define a protocol that will be implemented by the objects representing the arithmetic operations:
:- protocol(eval).
:- public(eval/1).
:- end_protocol.
The basic parametric object understands val/1 and contains the bind/2 table:
:- object(val(_X_), implements(eval)).
eval(X) :-
bind(_X_, X).
bind(a, 3).
bind(b, 4).
bind(c, 5).
:- end_object.
I exemplify here only the implementation for arithmetic addition:
:- object(_X_ + _Y_, implements(eval)).
eval(Result) :-
_X_::eval(X), _Y_::eval(Y),
Result is X + Y.
:- end_object.
Sample call (assuming the entities above are saved in an eval.lgt file):
% swilgt
...
?- {eval}.
% [ /Users/pmoura/Desktop/eval.lgt loaded ]
% (0 warnings)
true.
?- (val(a) + val(b))::eval(R).
R = 7.
This can be an interesting solution if you plan to implement more functionality other than expression evaluation. E.g. a similar solution but for symbolic differentiation of arithmetic expressions can be found at:
https://github.com/LogtalkDotOrg/logtalk3/tree/master/examples/symdiff
This solution will also work in the case of runtime generated expressions (term-expansion based solutions usually only work at source file compile time and at the top-level).
If you're only interested in expression evaluation, Capelli's solution is more compact and retains is/2 for evaluation. It can also be made more portable if necessary using Logtalk's portable term-expansion mechanism (but note the caveat in the previous paragraph).
This is perhaps not exactly what I was looking for, but I had an idea:
compute(val(X) + val(Y), Out) :-
bind(X, XVal),
bind(Y, YVal),
Out is XVal + YVal.
Now I can run the following query:
?- compute(val(a) + val(c), Out).
Out = 8.
Now I need to define compute for every arithmetic operation I'm interested in, then get my interpreter to run expressions through it.

Prolog rewriting equations

I am trying to create a rewrite predicate in SWI-Prolog that checks if an equation can be simplified then replaces the old one with the new one. I have tried to do the following:
Lets say I have the following equation x+0 and I want to replace/rewrite it with x.
I have tried the following:
simplify(X,X) :- primitive(X).
simplify(X,Y) :- evaluable(X), Y is X.
simplify_exp(X,Y) :- rewrite(X,X1), simplify(X1,Y).
simplify_exp(X,X).
primitive(X) :- atom(X).
rewrite(X+0,X).
rewrite(0+X,X).
rewrite(x+1+(y-1),x+y).
rewrite(X*X,X^2).
rewrite(X^0,1).
rewrite(0*X,0).
rewrite(X*N,N*X) :- number(N).
simplify(X) will return x to me, then I need to rewrite which is fine.
However when I have a longer equation lets say (power(a)+b)-(x+0), it won't find simplify(X) hence I cannot rewrite it.
Can I get any recommendation/help please?
The rewrite predicate can be re-written more concisely:
:- initialization(main).
:- set_prolog_flag(double_quotes, chars).
main :- rewrite(x*0,Output),writeln(Output).
rewrite(X+0,X1) :- rewrite(X,X1).
rewrite(0+X,X+0).
rewrite(X,X) :- atom(X);number(X).
rewrite(X+1+(Y-1),X1+Y1) :- rewrite(X,X1),rewrite(Y,Y1).
rewrite(X*X,X1^2) :- rewrite(X,X1).
rewrite(X^0,1).
rewrite(0*X,0).
rewrite(X*0,Output) :- rewrite(0*X,Output).
rewrite(X*N,N*X1) :- number(N),(\+number(X)),rewrite(X,X1).
rewrite(N*X,N*X1) :- rewrite(X*N,N*X1).
To simplify more complicated arithmetic expressions, you can use the Reduce-Algebraic-Expressions library.

Resources