DCG prolog returning multiple variable answers [duplicate] - prolog

If I have the below piece of code, how would I make it produce Answer= 5 and Answer2= 10?. I run the goal ?- test(Data),lpsolve(Data, [Answer1,Answer2]).
:-use_module(library(clpfd)).
test([the, variable, X, is, five,fullstop,
the,variable, Y, is, ten, fullstop]).
lpsolve(Data, [Answer,Answer2]):- sentence(Answer, Data,[]).
sentence(X) --> nounphrase, verbphrase(X).
nounphrase --> [the], [variable].
verbphrase(X) --> [X], [is], [five],[fullstop], {X = 5}.
sentence(Y) --> nounphrase, verbphrase(Y).
nounphrase --> [the], [variable].
verbphrase(Y) --> [Y], [is], [ten],[fullstop], {Y = 10}.
Example of a program that actually runs and is closely related is the following:
:-use_module(library(clpfd)).
test([the, variable, X, is, five,fullstop]).
lpsolve(Data, Answer):- sentence(Answer, Data,[]).
sentence(X) --> nounphrase, verbphrase(X).
nounphrase --> [the], [variable].
verbphrase(X) --> [X], [is], [five],[fullstop], {X = 5}.
I have just one sentence to test and the goal succeeds as shown below.
?- test(Data),lpsolve(Data, Answer).
Data = [the, variable, 5, is, five],
Answer = 5.
EDIT
I try the following as per the first comment:
:-use_module(library(clpfd)).
test([the, variable, x, is, five,fullstop,
the,variable, y, is, ten, fullstop]).
lpsolve(Data, Answer):- sentence(Answer, Data,[]).
sentence(X) --> nounphrase, verbphrase(X).
nounphrase --> [the], [variable].
verbphrase(X) --> [x], [is], [five],[fullstop], {X = 5}.
verbphrase(Y) --> [y], [is], [ten],[fullstop], {Y = 10}.
I get the following:
-? test(Data),lpsolve(Data, Answer).
false.

I'm not really sure what you're trying to do here, but I feel your DCG is broken down in completely strange ways and you may benefit from seeing another way to arrange it.
You have a list of variable bindings, so you should already be thinking in terms of obtaining a list of results rather than a single result:
sentences([S|Ss]) --> sentence(S), sentences(Ss).
sentences([]) --> [].
What is a sentence? It is a noun phrase and a verb phrase, in your simple system. But you have broken the noun and verb phrases apart incorrectly for English, where a sentence like "The variable X is 5" should be broken into a noun phrase subject "The variable X" and a verb phrase "is 5". Ideally, the verb phrase should be decomposed further into a verb another noun phrase, but we're ignoring that detail for now. I am looking for the verb "is" to relate it to the Prolog predicate =/2, and handling fullstop here:
sentence(N1=N2) --> nounphrase(N1), verbphrase(is, N2), [fullstop].
OK, so now we need your noun phrase:
nounphrase(N) --> [the, variable, N].
And your verb phrase:
verbphrase(is, V) --> [is], value(V).
I'm only handling the two decodings and I'm doing it implicitly in the DCG definition:
value(5) --> [five].
value(10) --> [ten].
You'll find this works for the use case you've defined above:
?- phrase(sentences(S), [the,variable,X,is,five,fullstop,the,variable,Y,is,ten,fullstop]).
S = [X=5, Y=10] ;
false.

Related

Left associative evaluation of a right recursive grammar in Prolog

I have an issue with evaluating a parsetree derived from a grammar. The parsetree is derived from this pice of code:
parse(block(LEFT_CURLY, STMTS, RIGHT_CURLY)) -->
left_curly(LEFT_CURLY),
statements(STMTS),
right_curly(RIGHT_CURLY).
statements(statements) -->
[].
statements(statements(ASSIGNMENT, STMTS)) -->
assignment(ASSIGNMENT),
statements(STMTS).
assignment(assignment(ID, ASSIGN_OP, EXPR, SEMICOLON)) -->
ident(ID),
assign_op(ASSIGN_OP),
expression(EXPR),
semicolon(SEMICOLON).
expression(expression(TERM)) -->
term(TERM).
expression(expression(TERM, SUB_OP, EXPR)) -->
term(TERM),
sub_op(SUB_OP),
expression(EXPR).
expression(expression(TERM, ADD_OP, EXPR)) -->
term(TERM),
add_op(ADD_OP),
expression(EXPR).
term(term(TERM)) -->
factor(TERM).
term(term(FACTOR, MULT_OP ,TERM)) -->
factor(FACTOR),
mult_op(MULT_OP),
term(TERM).
term(term(FACTOR, DIV_OP ,TERM)) -->
factor(FACTOR),
div_op(DIV_OP),
term(TERM).
factor(factor(FACTOR)) -->
int(FACTOR).
factor(factor(FACTOR)) -->
ident(FACTOR).
factor(factor(LEFT_PAR, EXPR, RIGHT_PAR)) -->
left_par(LEFT_PAR),
expression(EXPR),
right_par(RIGHT_PAR).
assign_op(assign_op) --> [=].
mult_op(mult_op) --> [*].
add_op(add_op) --> [+].
sub_op(sub_op) --> [-].
div_op(div_op) --> [/].
left_par(left_paren) --> ['('].
right_par(right_paren) --> [')'].
left_curly(left_curly) --> ['{'].
right_curly(right_curly) --> ['}'].
semicolon(semicolon) --> [;].
ident(ident(Y)) --> [Y] , {atom(Y)}.
int(int(X)) --> [X], {integer(X)}.
The resulting parseTree from parse/3 looks like this (ex. inpt { b = 4 - 2 - 1; }:)
T = block(left_curly,statements(assignment(ident(b),assign_op,expression(term(factor(int(4))),sub_op,expression(term(factor(int(2))),sub_op,expression(term(factor(int(1)))))),semicolon),statements),right_curly)
I've had some success with evaluating the expression, and saving variable results. But I am for now evaluating "bottom up" resulting in a right associative evaluation (3), which is not how math works. 4 - 2 - 1 != 3.
An example of the evaluation which evaluates 4 - 2 - 1 to 3:
evaluate(expression(TERM, SUBOP, EXPR), OtherVariables, RESULT) :-
SUBOP = sub_op,
!,
evaluate(TERM, OtherVariables, LHSResult),
evaluate(EXPR, OtherVariables, RHSResult),
RESULT is LHSResult - RHSResult.
evaluate(term(FACTOR), OtherVariables, RESULT) :-
evaluate(FACTOR, RESULT).
evaluate(factor(INT), RESULT) :-
evaluate(INT, RESULT).
evaluate(int(X), X).
Is there anyone who could give me a hint on how to move forward with this issue? I have been able to do this in Java, but my Prolog knowledge is not as good. Unfortunately I am not allowed to change the grammar or the parsing.
Your parse tree is very explicit about whether the input contains parentheses. For example:
?- phrase(expression(Expr), [4, -, 2, -, 1]).
Expr = expression(term(factor(int(4))), sub_op, expression(term(factor(int(2))), sub_op, expression(term(factor(int(1)))))) .
?- phrase(expression(Expr), [4, -, '(', 2, -, 1, ')']).
Expr = expression(term(factor(int(4))), sub_op, expression(term(factor(left_paren, expression(term(factor(int(2))), sub_op, expression(term(factor(int(1))))), right_paren)))) .
This is good, because we can tell where the user really wanted us to evaluate 4 - (2 - 1), or whether the input was 4 - 2 - 1 and should really be interpreted as (4 - 2) - 1.
By far the simplest way of doing this is by thinking about the problem not as "left-associative evaluation of a right-associative tree", but about the two separate problems of "evaluation of a tree" and "getting a left-associative tree into right-associative form". That is, don't try to be clever inside your evaluate predicate, but first reassociate the tree and then evaluate that new tree.
A sketch:
op_associativity(add_op, right).
op_associativity(sub_op, left).
op_associativity(mult_op, right).
op_associativity(div_op, left).
expression_reassociated(expression(X, Op, expression(Y, Op, Z)),
expression(expression(X, Op, Y), Op, Z)) :-
op_associativity(Op, left),
!.
expression_reassociated(Expression, Expression).
With a slightly massaged version of your evaluate, this already gives:
?- phrase(expression(Expr), [4, -, 2, -, 1]), expression_reassociated(Expr, Reassociated), evaluate(Reassociated, Result).
Expr = expression(term(factor(int(4))), sub_op, expression(term(factor(int(2))), sub_op, expression(term(factor(int(1)))))),
Reassociated = expression(expression(term(factor(int(4))), sub_op, term(factor(int(2)))), sub_op, expression(term(factor(int(1))))),
Result = 1 ;
false.
Note that expression_reassociated needs more work: It must reassociate sub-expressions as well. Once you have a complete working solution, you can think about reassociating "on the fly" during evaluation without building the intermediate tree. But it's probably not worth it, unless explicitly requested by your professor.
All that said, it would really be best if the DCG produced the correctly associated parse tree from the start, but I understand that you have constraints.

How to use normal clauses converted from DCG Prolog one?

I know DCG is only a syntactic sugar , as prolog translate them in normal Clauses.
So, for instance,
palindrome --> [].
palindrome --> [_].
palindrome --> [X], palindrome, [X].
/* it is translated into: */
palindrome(A, A).
palindrome([_|A], A).
palindrome([X|A], B) :- palindrome(A, C), C=[X|B].
My problem is, I want to avoid, to use the "phrase" clause, and accessing the normal code converting fron the DCG one.
If I try to ask for a palindrome sequence, it simply dosen't work.
For istance:
? palindrome([1,2],X).
X = [1, 2] .
I'd like to have the same result as:
?- phrase(palindrome,[1,2,1]).
true
?- phrase(palindrome,[1,2,X]).
X = 1
Without using phrase.
Thanks

DCG version for maplist/3

The following meta-predicate is often useful. Note that it cannot be called maplist//2, because its expansion would collide with maplist/4.
maplistDCG(_P_2, []) -->
[].
maplistDCG(P_2, [A|As]) -->
{call(P_2, A, B)},
[B],
maplistDCG(P_2, As).
There are several issues here. Certainly the name. But also the terminal [B]: should it be explicitly disconnected from the connecting goal?
Without above definition, one has to write either one of the following - both having serious termination issues.
maplistDCG1(P_2, As) -->
{maplist(P_2, As, Bs)},
seq(Bs).
maplistDCG2(P_2, As) -->
seq(Bs),
{maplist(P_2, As, Bs)}.
seq([]) -->
[].
seq([E|Es]) -->
[E],
seq(Es).
Does {call(P_2,A,B)}, [B] have advantages over [B], {call(P_2,A,B)}?
(And, if so, shouldn't maplist/3 get something like that, too?)
Let's put corresponding dcg and non-dcg variants side-by-side1:
dcg [B],{call(P_2,A,B)} and non-dcg Bs0 = [B|Bs], call(P_2,A,B)
maplistDCG(_,[]) --> []. % maplist(_,[],[]).
maplistDCG(P_2,[A|As]) --> % maplist(P_2,[A|As],Bs0) :-
[B], % Bs0 = [B|Bs],
{call(P_2,A,B)}, % call(P_2,A,B),
maplistDCG(P_2,As). % maplist(P_2,As,Bs).
dcg {call(P_2,A,B)},[B] and non-dcg call(P_2,A,B), Bs0 = [B|Bs]
maplistDCG(_,[]) --> []. % maplist(_,[],[]).
maplistDCG(P_2,[A|As]) --> % maplist(P_2,[A|As],Bs0) :-
{call(P_2,A,B)}, % call(P_2,A,B),
[B], % Bs0 = [B|Bs],
maplistDCG(P_2,As). % maplist(P_2,As,Bs).
Above, we highlighted the goal ordering in use now:
by maplist/3, as defined in this answer on SO and in the Prolog prologue
by maplistDCG//2, as defined in this question by the OP
If we consider that ...
... termination properties need to be taken into account and ...
... dcg and non-dcg variants should better behave the same2 ...
... we find that the variable should not be explicitly disconnected from the connecting goal. The natural DCG analogue of maplist/3 is maplistDCG//2 defined as follows:
maplistDCG(_,[]) -->
[].
maplistDCG(P_2,[A|As]) -->
[B],
{call(P_2,A,B)},
maplistDCG(P_2,As).
Footnote 1: To emphasize commonalities, we adapted variable names, code layout, and made some unifications explicit.
Footnote 2: ... unless we have really good reasons for their divergent behaviour ...

In Prolog DCGs, how to remove over general solutions?

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.

How to write optional in SWI-Prolog

I need to implement some rules by Prolog
ex:
S ---> A,[b],{c}.
Where:
[b] could happen once or none like 0 or 1 time
{c} could happen 0,1,2,...times
How can i write it?
Edit:
I used this:
:- op(700,xfx,--->).
s ---> [vp].
s ---> [vp,conj,vp].
s ---> [vp,conj,np].
vp ---> [feal_amr],
([mfoal_beh];[]),
([mfoal_beh];[]),
([bdl];[]),
[sefa_optional],
([hal];[]),
([shbh_gomla];[]),
([mfoal_motlk];[]).
It gives me an error "Full stop in clause-body? Cannot redefine ,/2"
in the comma in this line "vp ---> [feal_amr], ..."
Edit
I use "--->" because i have this
parse_topdown(Category,String,Reststring,[Category|Subtrees]) :-
Category ---> RHS,
matches(RHS,String,Reststring,Subtrees).
And "-->" gives an error with the operator ":-"?!!
this is my code for an Arabic Parser Code
I'm sorry for inconvenience but i am not an expert in Prolog
from your description
s --> [a], ([b] ; []), c_1.
c_1 --> [c], c_1 ; [].
some test pattern:
?- phrase(s, [a,b,c,c,c]).
true
?- phrase(s, [a]).
true
edit
about your code: you should use -->. Why you declare ---> (and not define it) ? That way you should write your own analyzer, you're not using DCG.
Note that [vp,conj,vp] it's a list of terminals,
Not sure about feal_amr,mfoal_beh, etc etc, but vp it's surely a nonterminal (it's rewritten).
Then I think you should write
s --> vp.
s --> vp,conj,vp.
s --> vp,conj,np.
vp -->
[feal_amr],
([mfoal_beh];[]),
([mfoal_beh];[]),
([bdl];[]),
[sefa_optional],
([hal];[]),
([shbh_gomla];[]),
([mfoal_motlk];[]).
% I hypotesize it's a comma.
conj --> [','].
edit as noted in comments, you are not using DCG, but your own interpreter. I tested it with a minimal example
:- op(700,xfx,--->).
s ---> [name,verb,names].
names ---> [name, conj, names].
names ---> [name].
names ---> [].
lex(anne, name).
lex(bob, name).
lex(charlie, name).
lex(call, verb).
lex(and, conj).
parse_topdown(Category,[Word|Reststring],Reststring,[Category,Word]) :-
lex(Word,Category).
parse_topdown(Category,String,Reststring,[Category|Subtrees]) :-
Category ---> RHS,
matches(RHS,String,Reststring,Subtrees).
matches([],String,String,[]).
matches([Category|Categories],String,RestString,[Subtree|Subtrees]) :-
parse_topdown(Category,String,String1,Subtree),
matches(Categories,String1,RestString,Subtrees).
and this program accepts 0,1, or more names:
?- parse_topdown(s,[anne,call,bob,and,charlie],R,P).
R = [],
P = [s, [name, anne], [verb, call], [names, [name, bob], [conj, and], [names|...]]] ;
R = [charlie],
P = [s, [name, anne], [verb, call], [names, [name, bob], [conj, and], [names]]] ;
R = [and, charlie],
P = [s, [name, anne], [verb, call], [names, [name, bob]]] ;
R = [bob, and, charlie],
P = [s, [name, anne], [verb, call], [names]] ;
false.
Note I leave R free, to examine partial matches. Coming back to your original question, you can see how the nonterminal names accepts 0,1,or many (separed by and) values.
Note that such interpreter will be very slow on any substantial input. I'd advise you to rewrite your grammar using DCG.
First, you probably want to lower-case S and A; Prolog uses initial caps for variable names.
One way to allow 'b' to occur once or not at all is to write something like this:
s --> a, b_optional, {c}.
b_optional --> [b].
b_optional --> [].
There is also syntax for writing the two rules for b_optional as a single rule, if you prefer; consult the chapter on definite clause grammars in your favorite Prolog text.
I don't know what you mean by c happening 0, 1, 2, ... times, so I don't think I can help you there.

Resources