As a follow up to this question which poses the problem
Return count of items in a list but if two identical items are next to each other then don't increment the count.
This code is the closest I came to solving this with DCG and semicontext.
lookahead(C),[C] -->
[C].
% empty list
% No lookahead needed because last item in list.
count_dcg(N,N) --> [].
% single item in list
% No lookahead needed because only one in list.
count_dcg(N0,N) -->
[_],
\+ [_],
{ N is N0 + 1 }.
% Lookahead needed because two items in list and
% only want to remove first item.
count_dcg(N0,N) -->
[C1],
lookahead(C2),
{ C1 == C2 },
count_dcg(N0,N).
% Lookahead needed because two items in list and
% only want to remove first item.
count_dcg(N0,N) -->
[C1],
lookahead(C2),
{
C1 \== C2,
N1 is N0 + 1
},
count_dcg(N1,N).
count(L,N) :-
DCG = count_dcg(0,N),
phrase(DCG,L).
What is the correct way to solve the problem using DCG with semicontext on the clause head?
Would like to know if the variation with the semicontext on the clause head is possible or not. If possible then working example code is desired, if not possible then an explanation is desired.
I think this is using semi context notation correctly. I am counting using 0,s(0),...
% Constraint Logic Programming
:- use_module(library(dif)). % Sound inequality
:- use_module(library(clpfd)). % Finite domain constraints
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
state(S), [state(S)] --> [state(S)].
state(S, s(S)), [state(s(S))] --> [state(S)].
keep_state(S,I),[state(S)] --> [state(S)],[I].
end_state(S) -->[state(S)],[].
lookahead(C),[S,C] -->
[S,C].
count_dcg(S,S) -->
state(S), %might not need this
end_state(S).
/* Can be used get the length of a list
count_dcg(S,S2) -->
state(S,S1),
keep_state(S1,_),
count_dcg(S1,S2),
{}.
*/
%last item.
count_dcg(S,S1) -->
state(S,S1),
keep_state(S1,_C),
list(R),
{R = [state(_)]}.
%Two the same dont increase state
count_dcg(S,S1) -->
state(S), %might not need this
keep_state(S,C1),
lookahead(C1),
count_dcg(S,S1).
%Two different increase state
count_dcg(S,S2) -->
state(S,S1),
keep_state(S1,C1),
lookahead(C2),
{
dif(C1,C2)
},
count_dcg(S1,S2).
count(L,S) :-
phrase(count_dcg(0,S),[state(0)|L]).
This does not work as well as I hoped for cases like:
65 ?- count([a,b,X,c],L).
X = b,
L = s(s(s(0))) ;
;
X = c,
L = s(s(s(0))) .
You can convert peano with:
natsx_int(0, 0).
natsx_int(s(N), I1) :-
I1 #> 0,
I2 #= I1 - 1,
natsx_int(N, I2).
or you can change the state predicates:
state(S), [state(S)] --> [state(S)].
state(S, S2), [state(S2)] --> [state(S)],{S2#=S+1}.
How about:
:-use_module(library(clpfd)).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
lookahead(C),[C] -->
[C].
count_dcg(N,N) --> [].
count_dcg(N0,N) --> %last item.
[_],
list(R),
{R = [], N #=N0+1}.
count_dcg(N0,N) -->
[C1],
lookahead(C1),
count_dcg(N0,N).
count_dcg(N0,N) -->
[C1],
lookahead(C2),
{
dif(C1,C2),
N1 #= N0 + 1
},
count_dcg(N1,N).
count(L,N) :-
phrase(count_dcg(0,N),L).
Related
I have been trying to convert a section of Prolog code I created to represent a basic finite automaton into a DCG. Basically it ensures that an acceptable input would be one where the third last element in a string of 0s and 1s is a 1.
E.g. [1,0,0,1,0,1] is acceptable while [1,0,1,0,0,0] is not.
accept(L) :- steps(q0,L,F), final(F).
steps(Q,[],Q).
steps(Q,[H|T],Q2) :- tran(Q,H,Qn), steps(Qn,T,Q2).
final(q1).
tran(Y,0,n0) :- Y = q0; Y = q1; Y = n0.
tran(Y,1,n1) :- Y = q0; Y = q1; Y = n0.
tran(n1,X,h1):- X = 0 ; X = 1.
tran(h1,X,q1):- X = 0 ; X = 1.
My problem is essentially with the second clause of the steps predicate where the output of "tran(Q,H,Qn)" is used as an input for steps(Qn,T,Q2), in this case being the variable Qn.
The DCG I have come up with is as follows :
accept(L) --> final(F),{F = steps(q,L)}.
steps(Q,[]) --> [Q].
steps(Q,[H|T]) --> steps(E,T), {E = tran(Q,H)}.
final(F) --> [q1], {F = q1}.
tran(Y,0) --> [n0], {Y = q;Y = q1;Y = n0}.
tran(Y,1) --> [n1], {Y = q;Y = q1;Y = n0}.
tran(n1,X) -->[h1], {X = 0; X = 1}.
tran(h1,X) -->[q1], {X = 0; X = 1}.
I am basically wondering if there is another way of ensuring that the variable E, in the second line of DCG can be used to represent tran(Q,H) instead of defining it as an extra goal which has not been working so far.
DCGs describe lists. Unlike everything else in Prolog, they describe these lists implicitly. Every value you compute in Prolog needs to be passed out of a predicate through an argument -- except for the lists described by DCGs, which you do not represent by an argument. They are instead represented as an implicit DCG state. (There are some uses for having the list as an argument as well, but it's not common.)
What this means is that when you convert a predicate to a DCG, you remove the list argument. But you must keep all other arguments so that you can communicate with the rest of the program.
So, for example, if you have the following predicate:
abc(A, B, C, [A, B, C]).
?- abc(a, b, c, ABC).
ABC = [a, b, c].
To convert it to a DCG that describes the list [A, B, C] you remove the list from the arguments but keep all other arguments:
abc(A, B, C) -->
[A, B, C].
?- phrase(abc(a, b, c), ABC).
ABC = [a, b, c].
What this means for your program is that your predicate
accept(List) :- ...
will turn into a DCG without arguments:
accept --> ...describe the list somehow...
and your steps predicate:
steps(Q, Steps, Q2) :- ...
will keep the states Q and Q2 as arguments but will remove the list argument:
steps(Q, Q2) --> ...describe the steps somehow...
With this knowledge, the first part of the translation is fairly mechanical:
accept -->
steps(q0, F),
{ final(F) }.
steps(Q, Q) -->
[].
steps(Q, Q2) -->
tran(Q, Qn),
steps(Qn, Q2).
As for the rest, you had some confusion in your transition DCG because suddenly it looked like you were trying to describe a list of states rather than a list of input symbols. This is partly because you chose bad variable names. This is not entirely your fault; many Prolog texts were written by people with a mathematical background, and written at times when books were printed on paper (which was expensive, so programs had to be more compact than anything else) or stored on tiny, slow storage devices (which again meant they had to be compact above all else) or viewed on tiny computer screens (which again meant that they had to be compact above all else). We don't have these restrictions anymore, so we can free ourselves from the shackles of the past. It is your responsibility to choose good variable names despite what outdated Prolog traditions teach you. By all of which I mean to say: If a variable describes a state, it should be called State instead of Y (or, yes, in automata theory Q can be canonical), and if a variable describes a symbol, it should be called Symbol instead of X.
Anyway. Here is a fixed version:
tran(Q, n0) --> [0], {Q = q0 ; Q = q1 ; Q = n0}.
tran(Q, n1) --> [1], {Q = q0 ; Q = q1 ; Q = n0}.
tran(n1, h1) --> [Symbol], {Symbol = 0 ; Symbol = 1}.
tran(h1, q1) --> [Symbol], {Symbol = 0 ; Symbol = 1}.
The original predicate behaves like this:
?- accept([1, 0, 0, 1, 0, 1]).
true ;
false.
?- accept([1, 0, 1, 0, 0, 0]).
false.
And the fixed DCG version behaves the same:
?- phrase(accept, [1, 0, 0, 1, 0, 1]).
true ;
false.
?- phrase(accept, [1, 0, 1, 0, 0, 0]).
false.
My impression is that you're overengineering... to keep things simple, an abstraction (DCGs, in our case) should be used for its strengths.
So, I would suggest to 'invert' your encoding schema: let's predicates be our automaton states, following input in direct way, controlled by DCG normal behaviour, and encode in predicate arguments the state payload, if any (in the example code there is none). For instance
/* File: dcg_autom.pl
Author: Carlo,,,
Created: Dec 8 2020
Purpose: https://stackoverflow.com/q/65191963/874024
*/
:- module(dcg_autom,
[accept/1
]).
accept(S) :- phrase(start, S).
start --> q0.
final --> []. % overkill, I know...
q0 --> [0], n0.
q0 --> [1], n1.
n0 --> [0], n0.
n0 --> [1], n1.
n1 --> [_], h1.
h1 --> [_], q1.
q1 --> final.
q1 --> [0], n0.
q1 --> [1], n1.
I'm suggesting this architecture change because a finite state automaton it's very easy to implement in basic Prolog, there is really no need to fiddle with DCGs...
Willing to get the list of visited states, the (boring) changes to the code could be
accept(S,L) :- phrase(start(L), S).
start([start|L]) --> q0(L).
final([final]) --> []. % overkill, I know...
q0([q0|L]) --> [0], n0(L).
q0([q0|L]) --> [1], n1(L).
n0([n0|L]) --> [0], n0(L).
n0([n0|L]) --> [1], n1(L).
n1([n1|L]) --> [_], h1(L).
h1([h1|L]) --> [_], q1(L).
q1([q1|L]) --> final(L).
q1([q1|L]) --> [0], n0(L).
q1([q1|L]) --> [1], n1(L).
and then we have
?- accept([1,0,0,1,0,1],L).
L = [start, q0, n1, h1, q1, n1, h1, q1, final] ;
false.
Currently, in my code, I have a list of words arranged as follows:
lexical_item --> [a,m].
lexical_item --> [e,s,t].
lexical_item --> [r,a,p,i,d].
...
That is, when I need to add a new word (eg. 'car'), I have to manually add it as [c,a,r]...
How can I have in my code something like the following:
lexical_item --> [am].
lexical_item --> [est].
lexical_item --> [rapid].
...
And, when i run my code, automatically transform 'rapid' in 'r,a,p,i,d', instead of having to previously add the word with all the letters divided by a comma?
automatically transform 'rapid' in 'r,a,p,i,d'
I'm not sure why all commenters failed to point out that what you want is atom_chars/2:
?- atom_chars(rapid, Chars).
Chars = [r, a, p, i, d].
?- atom_chars(Atom, [r, a, p, i, d]).
Atom = rapid.
The idea is to separate your database of words (represented as atoms) from the lexical_item//0 DCG rule, and to do the conversion inside that:
word(am).
word(est).
word(rapid).
lexical_item -->
{ word(W),
atom_chars(W, Chars) },
list(Chars).
list([]) -->
[].
list([X|Xs]) -->
[X],
list(Xs).
As written, the lexical_item//0 rule can be used very generally, to recognize words, reject non-words, and to enumerate all the words in the database:
?- phrase(lexical_item, [r,a,p,i,d]).
true.
?- phrase(lexical_item, [s,o,m,e,t,h,i,n,g]).
false.
?- phrase(lexical_item, Item).
Item = [a, m] ;
Item = [e, s, t] ;
Item = [r, a, p, i, d].
This is great from a logical point of view, but operationally, it would be more efficient to have the goals in the rule in the exact opposite order.
I have a text file containing a sequence. For example:
GGGGGGGGAACCCCCCCCCCTTGGGGGGGGGGGGGGGGAACCCCCCCCCCTTGGGGGGGG
I have wrote the following DCG to find the sequence between AA and TT.
:- use_module(library(pio)).
:- use_module(library(dcg/basics)).
:- portray_text(true).
process(Xs) :- phrase_from_file(find(Xs), 'string.txt').
anyseq([]) -->[].
anyseq([E|Es]) --> [E], anyseq(Es).
begin --> "AA".
end -->"TT".
find(Seq) -->
anyseq(_),begin,anyseq(Seq),end, anyseq(_).
I query and I get:
?- process(Xs).
Xs = "CCCCCCCCCC" ;
Xs = "CCCCCCCCCCTTGGGGGGGGGGGGG...CCCCC" ;
Xs = "CCCCCCCCCC" ;
false.
But I dont want it to find the second solution or ones like it. Only the solutions between one pair of AA and TTs not all combinations. I have a feeling I could use string_without and string in library dcg basiscs but I dont understand how to use them.
your anyseq//1 is identical to string//1 from library(dcg/basics), and shares the same 'problem'.
To keep in control, I would introduce a 'between separators' state:
elem(E) --> begin, string(E), end, !.
begin --> "AA".
end -->"TT".
find(Seq) -->
anyseq(_),elem(Seq).
anyseq([]) -->[].
anyseq([E|Es]) --> [E], anyseq(Es).
process(Xs) :-
phrase(find(Xs), `GGGGGGGGAACCCCCCCCCCTTGGGGGGGGGGGGGGGGAACCCCC+++CCCCCTTGGGGGGGG`,_).
now I get
?- process(X).
X = "CCCCCCCCCC" ;
X = "CCCCC+++CCCCC" ;
false.
note the anonymous var as last argument of phrase/3: it's needed to suit the change in 'control flow' induced by the more strict pattern used: elem//1 is not followed by anyseq//1, because any two sequences 'sharing' anyseq//1 would be problematic.
In the end, you should change your grammar to collect elem//1 with a right recursive grammar....
First, let me suggest that you most probably misrepresent the problem, at least if this is about mRNA-sequences. There, bases occur in triplets, or codons and the start is methionine or formlymethionine, but the end are three different triplets. So most probably you want to use such a representation.
The sequence in between might be defined using all_seq//2, if_/3, (=)/3:
mRNAseq(Cs) -->
[methionine],
all_seq(\C^maplist(dif(C),[amber,ochre,opal]), Cs),
( [amber] | [ochre] | [opal]).
or:
mRNAseq(Cs) -->
[methionine],
all_seq(list_without([amber,ochre,opal]), Cs),
( [amber] | [ochre] | [opal]).
list_without(Xs, E) :-
maplist(dif(E), Xs).
But back to your literal statement, and your question about declarative names. anyseq and seq mean essentially the same.
% :- set_prolog_flag(double_quotes, codes). % pick this
:- set_prolog_flag(double_quotes, chars). % or pick that
... --> [] | [_], ... .
seq([]) -->
[].
seq([E|Es]) -->
[E],
seq(Es).
mRNAcontent(Cs) -->
...,
"AA",
seq(Cs),
"TT",
{no_TT(Cs)}, % restriction
... .
no_TT([]).
no_TT([E|Es0]) :-
if([E] = "T",
( Es0 = [F|Es], dif([F],"T") ),
Es0 = Es),
no_TT(Es).
The meaning of no_TT/1 is: There is no sequence "TT" in the list, nor a "T" at then end. So no_TT("T") fails as well, for it might collide with the subsequent "TT"!
So why is it a good idea to use pure, monotonic definitions? You will most probably be tempted to add restrictions. In a pure monotonic form, restrictions are harmless. But in the procedural version suggested in another answer, you will get simply different results that are no restrictions at all.
I'm writing a calculator in Prolog that reads natural language questions and returns a number answer for a class assignment, and I'm nearly complete. However, when I input a sentence the program simply returns 'Yes' and then quits. As far as I can tell it doesn't even read in the sentence. This is my first time writing in Prolog, so I have no clue what is wrong. Any help would be greatly appreciated.
My code:
:- consult('aux.p').
accumulator(0).
start :-
write('Cranky Calculator'), nl,
write('-----------------'), nl,
cvt.
cvt :-
write('What do ya want?'), nl,
read_sentence(Question),
butlast(Question, Questio),
Questio \== [quit], !,
(
phrase(sentence(Value), Questio, []),
write(Value);
write_string('Stop it with your gibberish!')
), nl,
cvt.
cvt.
reset(V) :-
retract(accumulator(_)),
assert(accumulator(V)).
accumulate('plus', N, Value) :-
{Temp is accumulator(_)},
{Value is Temp + N},
reset(Value).
accumulate('minus', N, Value) :-
{Temp is accumulator(_)},
{Value is Temp - N},
reset(Value).
accumulate('divided', N, Value) :-
{Temp is accumulator(_)},
{Value is Temp / N},
reset(Value).
accumulate('times', N, Value) :-
{Temp is accumulator(_)},
{Value is Temp * N},
reset(Value).
accumulate(N1, 'plus', N2, Value) :-
{Value is N1 + N2},
reset(Value).
accumulate(N1, 'minus', N2, Value) :-
{Value is N1 - N2},
reset(Value).
accumulate(N1, 'divided', N2, Value) :-
{Value is N1 / N2},
reset(Value).
accumulate(N1, 'times', N2, Value) :-
{Value is N1 * N2},
reset(Value).
%------------------base productions---------------------
% sentence can be to an entirely new question or simply be an addition
% to the previous one
sentence(V) --> base(V1), {V is V1}.
sentence(V) --> additional(V1), {V is V1}.
sentence --> [].
base(Value) -->
pro, be, number(N1), oper(OP), number(N2), qmark,
{
accumulate(N1, OP, N2, V), {Value is V}
}.
additional(Value) -->
oper(OP), number(N), qmark,
{
accumulate(OP, N, V), {Value is V}
}.
pro --> [what].
pro --> [how], [much].
be --> [is].
number(N) --> five_digit(N1), {N is N1}.
five_digit(N) --> ten_thousands(V1), four_digit(V2), {N is 1000 * V1 + V2}.
four_digit(N) --> thousands(V1), three_digit(V2), {N is 1000 * V1 + V2}.
three_digit(N) --> hundreds(V1), two_digit(V2), {N is 100 * V1 + V2}.
two_digit(N) --> tens(V1), one_digit(V2), {N is V1 + V2}.
two_digit(N) --> teens(V), {N is V}.
one_digit(N) --> digit(V), {N is V}.
one_digit(0) --> [].
ten_thousands(T) --> tens(V), thousand, {T is V}.
ten_thousands(T) --> tens(V), {T is V}.
ten_thousands(T) --> teens(V), thousand, {T is V}.
ten_thousands(0) --> [].
thousands(T) --> digit(V), thousand, {T is V}.
thousands(0) --> [].
hundreds(T) --> digit(V), hundred, {T is V}.
hundreds(0) --> [].
thousand --> [thousand].
hundred --> [hundred].
digit(1) --> [one].
digit(2) --> [two].
digit(3) --> [three].
digit(4) --> [four].
digit(5) --> [five].
digit(6) --> [six].
digit(7) --> [seven].
digit(8) --> [eight].
digit(9) --> [nine].
tens(20) --> [twenty].
tens(30) --> [thirty].
tens(40) --> [fourty].
tens(50) --> [fifty].
tens(60) --> [sixty].
tens(70) --> [seventy].
tens(80) --> [eighty].
tens(90) --> [ninety].
teens(10) --> [ten].
teens(11) --> [eleven].
teens(12) --> [twelve].
teens(13) --> [thirteen].
teens(14) --> [fourteen].
teens(15) --> [fifteen].
teens(16) --> [sixteen].
teens(17) --> [seventeen].
teens(18) --> [eighteen].
teens(19) --> [nineteen].
oper(plus) --> [plus].
oper(plus) --> [and].
oper(minus) --> [minus].
oper(divided) --> ['divided by'].
oper(times) --> [times].
qmark --> ['?'].
The output I get looks like:
|: what is twelve plus two?
Yes
I took your code as a spec for a calculator that also gives the
result as text. The idea here is to combine DCG and CLP(FD).
CLP(FD) is constraint solving for finite domains. Finite domains
should be enough for your calculator. To enable CLP(FD) you have
first to load the appropriate library. In Jekejeke Minlog this
is done as follows:
:- ensure_loaded(library('clpfd.px')).
The code has first a section that can not only recognize numbers
but also generate text for numbers. This is mainly the part where
DCGs are combined with CLP(FD):
number(N) --> {N #= 1000 * V1 + 100 * V2 + V3}, thousands(V1),
hundreds(V2), two_digit_opt(V3).
thousands(N) --> two_digit(N), thousand.
thousands(0) --> [].
thousand --> [thousand].
hundreds(N) --> digit(N), hundred.
hundreds(0) --> [].
hundred --> [hundred].
two_digit_opt(N) --> two_digit(N).
two_digit_opt(0) --> [].
two_digit(N) --> {N #= V1*10 + V2}, tens(V1), digit_opt(V2).
two_digit(N) --> {N #= V+10}, teens(V).
two_digit(N) --> digit(N).
digit_opt(N) --> digit(N).
digit_opt(0) --> [].
digit(1) --> [one].
digit(2) --> [two].
digit(3) --> [three].
digit(4) --> [four].
digit(5) --> [five].
digit(6) --> [six].
digit(7) --> [seven].
digit(8) --> [eight].
digit(9) --> [nine].
tens(2) --> [twenty].
tens(3) --> [thirty].
tens(4) --> [fourty].
tens(5) --> [fifty].
tens(6) --> [sixty].
tens(7) --> [seventy].
tens(8) --> [eighty].
tens(9) --> [ninety].
teens(0) --> [ten].
teens(1) --> [eleven].
teens(2) --> [twelve].
teens(3) --> [thirteen].
teens(4) --> [fourteen].
teens(5) --> [fifteen].
teens(6) --> [sixteen].
teens(7) --> [seventeen].
teens(8) --> [eighteen].
teens(9) --> [nineteen].
Here is a prove that the bidirectionality works:
?- phrase(number(X),[fifty,five]).
X = 55 ;
No
?- phrase(number(55),X).
X = [fifty,five] ;
No
Adding the calculator was straight forward. I didn't use assert/retract,
I simply using an argument in an infinite loop. I don't know how healthy
this is for your Prolog system, especially since we now inbetween touch
the constraint store. At least in Jekejeke Minlog as of version 0.7.2
the constraint store will not yet be completely recycled, so that one
cannot run the loop indefinitely.
But to show how all the pieces can be put together, the loop solution
is fine. The code reads as follows:
loop(S) :-
write('> '),
flush_output,
read(L),
phrase(cmd(C),L),
do(C,S,T),
phrase(number(T),M),
write(M), nl,
!, loop(T).
loop(S) :-
write('?'), nl,
loop(S).
do(set(N),_,N).
do(add(N),S,T) :- T is S+N.
do(sub(N),S,T) :- T is S-N.
cmd(set(N)) --> factor(N).
cmd(add(N)) --> [plus], factor(N).
cmd(sub(N)) --> [minus], factor(N).
factor(M) --> number(N), more(N, M).
more(N, M) --> [times], number(H), {J is N*H}, more(J,M).
more(N, M) --> [divided, by], number(H), {J is N//H}, more(J,M).
more(N, N) --> [].
And here is an example execution:
?- loop(0).
> [eleven,times,eleven].
[one,hundred,twenty,one]
> [minus,sixty,six].
[fifty,five]
Here is a little how to for the Jekejeke CLP(FD)
Jekejeke Minlog Desktop Installation
https://www.youtube.com/watch?v=6ZipaIrxSFQ
Jekejeke Minlog Android Installation
https://www.youtube.com/watch?v=Y2P7cEuOIws
cal(cal(1, plus, 2), minus, 3)
I need to get a result from it. How could I do that?
I'm pretty damaged by prolog. T.T
the AST is generated by calling:
?- calculations(Tree,[1,+,2,-,3],[]).
Tree = cal(cal(1, plus, 2), minus, 3) .
on the following DCG code:
calculations(VV) -->
vv(VV).
calculations(ResultTree) -->
vv(VV1), more_calculations(VV1,ResultTree).
more_calculations(VV1,cal(VV1,Operator,VV2)) -->
more_calculation(Operator,VV2).
more_calculations(VV1,ResultTree) -->
more_calculation(Operator1,VV2),
more_calculations(cal(VV1,Operator1,VV2),ResultTree).
more_calculation(Operator,VV) -->
operator(Operator),vv(VV).
vv(Name) --> var_name(Name).
vv(Value) --> var_value(Value).
operator(plus) --> [+].
operator(minus) --> [-].
var_name(Name) -->
[Name],{check_name(Name),\+member(Name,[write,read,begin,end,while])}.
var_value(Value) -->[Value],{number(Value)}.
check_name(N):-
catch(atom_chars(N, L), _, fail),
is_lower(L).
is_lower([]).
is_lower([H|T]) :-
catch(char_type(H, lower), _, fail),
is_lower(T).
There are many ways to do this, depending upon the bigger picture of what you're doing and what your goals are. But here is one possibility:
evaluate(cal(X, Op, Y), Result) :-
evaluate(X, Xr),
evaluate(Y, Yr),
Exp =.. [Op, Xr, Yr, Result],
call(Exp).
evaluate(X, X) :- number(X).
plus(X, Y, R) :- R is X + Y.
minus(X, Y, R) :- R is X - Y.
evaluate/2 assumes that you pass it something that looks like a number or a cal/3 where the parameters to cal/3 are an operand, an operator, and another operand, respectively. You write a predicate to evaluate each individual operator, and they assume the operands have been reduced to numbers.
Example:
evaluate(cal(cal(2, plus, 3), minus, 8), Result).
Gives:
Result = -3.
In the stated example:
| ?- calculations(Tree,[1,+,2,-,3],[]), evaluate(Tree, Result).
Result = 0
Tree = cal(cal(1,plus,2),minus,3) ? a
no