I need some help in prolog, which is pretty new to me. I have to design a small arithmetic computer. The expression to be evaluated will be represented as a list for example:
?-evaluate([2,+,4,*,5,+,1,*,2,*,3],R).
I am trying to do this by designing two predicates one called parse to transform my list for example:
?-parse([1,+,2,*,3],PF).
PF=[+,1,[*,2,3]]
and another one to evaluate the new expression.
?-evpf([+,1,[*,2,3]],R).
R=7
I have problems with the first part, can anyone help my with the code?
Parsing (= converting a list to an abstract syntax tree) is easy with DCGs:
list_ast(Ls, AST) :- phrase(expression(AST), Ls).
expression(E) --> term(T), expression_r(T, E).
expression_r(E0, E) --> [+], term(T), expression_r(E0+T, E).
expression_r(E0, E) --> [-], term(T), expression_r(E0-T, E).
expression_r(E, E) --> [].
term(T) --> power(P), term_r(P, T).
term_r(T0, T) --> [*], power(P), term_r(T0*P, T).
term_r(T0, T) --> [/], power(P), term_r(T0/P, T).
term_r(T, T) --> [].
power(P) --> factor(F), power_r(F, P).
power_r(P0, P0^P) --> [^], factor(P1), power_r(P1, P).
power_r(P, P) --> [].
factor(N) --> [N], { number(N) }.
factor(E) --> ['('], expression(E), [')'].
To actually evaluate the expression, you can then use the built-in predicate is/2. Sample query:
?- list_ast([2,+,4,+,5,+,1,+,2,*,3], Ast), V is Ast.
Ast = 2+4+5+1+2*3,
V = 18 ;
false.
Related
I know there have been questioned asked about this before but I still haven't been able to figure out whats wrong. I'm trying to create a DCG that can handle subject/object distinction, singular/plural distinction, capable of producing parse trees and make use of a separate lexicon.
I have this code:
lex(the,det,_).
lex(a,det,singular).
lex(man,n,singular).
lex(men,n,plural).
lex(apple,n,singular).
lex(apples,n,plural).
lex(eat,v,plural).
lex(eats,v,singular).
lex(i,pronoun,singular,subject).
lex(we,pronoun,plural,subject).
lex(me,pronoun,singular,object).
lex(us,pronoun,plural,object).
lex(you,pronoun,_,_).
lex(he,pronoun,singular,subject).
lex(she,pronoun,singular,subject).
lex(him,pronoun,singular,object).
lex(her,pronoun,singular,object).
lex(they,pronoun,plural,subject).
lex(them,pronoun,plural,object).
lex(it,pronoun,singular,_).
s(s(NP, VP), Q, P) --> np(NP, Q, P), vp(VP, Q).
np(np(DET, N), Q, _) --> det(DET, Q), n(N, Q).
np(np(PRONOUN), Q, P) --> pronoun(PRONOUN, Q, P).
vp(vp(V, NP), Q) --> v(V, Q), np(NP, _, object).
vp(vp(V), Q) --> v(V, Q).
det(det(W), Q) --> [W], {lex(W, det, Q)}.
pronoun(pronoun(W), Q, P) --> [W], {lex(W, pronoun, Q, P)}.
n(n(W), Q) --> [W], {lex(W, n, Q)}.
v(v(W), Q) --> [W], {lex(W, v, Q)}.
when I test it with s(X,[he,eats,the,apple],[]). I want to get the output
X = s(np(pronoun(he, singular, subject)), vp(v(eats, singular), np(det(the, singular), n(apple, singular, object)))).
But I get the error, uncaught exception: error(existence_error(procedure,s/3),top_level/0). and
ERROR: Undefined procedure: s/3 However, there are definitions for: s/5
ERROR: Stream user_input:6:1 Syntax error: Unexpected end of file
I tried changing it to
s(s(NP, VP)) --> np(NP, Q, P), vp(VP, Q).
but then I get the output: X = s(np(pronoun(he)),vp(v(eats),np(det(the),n(apple))))
I can't figure out where I'm going wrong. Any advice is appreciated.
Use the phrase/2 interface predicate to invoke a DCG:
?- phrase(s(A,B,C), [he,eats,the,apple]).
A = s(np(pronoun(he)), vp(v(eats), np(det(the), n(apple)))),
B = singular,
C = subject ;
false.
I am trying to convert a Prolog predicate into DCG code. Even if I am familiar with grammar langage I have some troubles to understand how DCG works with lists and how I am supposed to use it.
Actually, this is my predicate :
cleanList([], []).
cleanList([H|L], [H|LL]) :-
number(H),
cleanList(L, LL),
!.
cleanList([_|L], LL) :-
cleanList(L, LL).
It is a simple predicate which removes non-numeric elements.
I would like to have the same behaviour writes in DCG.
I tried something like that (which does not work obviously) :
cleanList([]) --> [].
cleanList([H]) --> {number(H)}.
cleanList([H|T]) --> [H|T], {number(H)}, cleanList(T).
Is it possible to explain me what is wrong or what is missing ?
Thank you !
The purpose of DCG notation is exactly to hide, or better, make implicit, the tokens list. So, your code should look like
cleanList([]) --> [].
cleanList([H|T]) --> [H], {number(H)}, cleanList(T).
cleanList(L) --> [H], {\+number(H)}, cleanList(L).
that can be made more efficient:
cleanList([]) --> [].
cleanList([H|T]) --> [H], {number(H)}, !, cleanList(T).
cleanList(L) --> [_], cleanList(L).
A style note: Prologgers do prefers to avoid camels :)
clean_list([]) --> [].
etc...
Also, I would prefer more compact code:
clean_list([]) --> [].
clean_list(R) --> [H], {number(H) -> R = [H|T] ; R = T}, clean_list(T).
List is the list of values in leaf nodes of a binary tree and I am trying to figure out how to output just that. This is giving me all the nodes but I need just the leaves.
lea(nil,[]).
lea(t(X,L,R),[X|L]) :-
lea(L,L1),
lea(R,L2),
append(L1,L2,L).
Running this gives me:
?- lea(t(a,t(b,t(d,nil,nil),t(e,nil,nil)),t(c,nil,t(f,t(g,nil,nil),nil))),
List).
List = [a, b, d, e, c, f, g]
but I need
List = [d, e,g]
Is it possible.
Let's use a DCG - a Definite Clause Grammar. We start with your original definition:
lea(T, L) :-
phrase(values(T), L).
values(nil) -->
[].
values(t(X,L,R)) -->
[X],
values(L),
values(R).
Now, we need to restrict ourselves to those t/3 that are leaves. One possibility is to enumerate all cases:
lea2(T, L) :-
phrase(leaves(T), L).
leaves(nil) -->
[].
leaves(t(X,nil,nil)) -->
[X].
leaves(t(_,L,R)) -->
{ dif(L+R,nil+nil) },
leaves(L),
leaves(R).
It would be even better and more efficient to use a conditional construct similar to if_/3. I want to leave this to someone interested.
First, we extend if_/3 to work with DCG's:
if_(C_1, Then_0, Else_0) --> % if_//3
{ call(C_1, Truth) },
{ functor(Truth, _, 0) }, % safety check
( { Truth == true } -> phrase(Then_0)
; { Truth == false }, phrase(Else_0)
).
Using if_//3 and (=)/3 we can handle non-nil tree nodes with one clause (instead of two):
lea3(T, Ls) :-
phrase(leaves(T), Ls).
leaves(nil) --> [].
leaves(t(X,L,R)) -->
if_(L-R = nil-nil, [X], []),
leaves(L),
leaves(R).
The same solution, not so far from first implementation, can be expressed as:
lea(nil, []).
lea(t(X, nil, nil), [X]).
lea(t(_, A, B), L) :-
lea(A, L1),
lea(B, L2),
append(L1, L2, L)
L \= [].
The last row (L \= []) can be removed (if you accept the possibility of find every solution).
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
I'm looking for a way to build an Expression Tree in Prolog. I already did some experiments and came up with the following working code (that will only handle constants and the plus expression):
const(_).
plus(_, _).
eval(const(R), R).
eval(plus(A, B), R) :- number(A), number(B), R is A+B.
eval(plus(A, B), R) :- number(A), eval(B, B_R), R is A+B_R.
eval(plus(A, B), R) :- eval(A, A_R), number(B), R is A_R+B.
eval(plus(A, B), R) :- eval(A, A_R), eval(B, B_R), R is A_R+B_R.
Is there any simpler alternative to this approach? Will I have to define these 4 cases for each one of the operators I plan on adding to my program?
See here another schema, exploiting DCG and (a kind of) lazy evaluation:
/*
File: dcg_calculator.pl
Author: Carlo,,,
Created: Aug 16 2011
Purpose: associativity and precedences in calculator
*/
:- module(dcg_calculator, [dcg_calculator/2, expr//1]).
%- [library(http/dcg_basics)]. obsolete
:- [library(dcg/basics)].
/* usage
?- dcg_calculator("1+(-2-2)",S),V is S.
S = 1+ (-2-2),
V = -3 ;
false.
*/
dcg_calculator(Formula, IsEvaluable) :-
phrase(expr(IsEvaluable), Formula, []).
expr(Evaluable) -->
sum(Evaluable).
sum(S) -->
product(P), sum_1(P, S).
sum_1(L, S) -->
"+", product(P), sum_1(L + P, S);
"-", product(P), sum_1(L - P, S);
{L = S}.
product(P) -->
value(V), product_1(V, P).
product_1(V, P) -->
"*", value(U), product_1(V * U, P);
"/", value(U), product_1(V / U, P);
{V = P}.
% value(V) -->
% {var(V)} -> {V=0 /* between(0, 9, V)*/ }, "0".
value(V) -->
"(", expr(V), ")" ;
number(V).
Using grammars to model data structures it's a very useful technique in Prolog. The grammar used it's an implementation of PEGs. Dependency from SWI-Prolog it's very limited, just number//1.
I think this should do it, though I'm not familiar with the construct pred1(pred2(...)...) :- ... (my Prolog is very rusty).
eval(A, A) :- number(A).
eval(plus(A, B), R) :- eval(A, A_R), eval(B, B_R), R is A_R+B_R.