parsing stdin with dcg - prolog

I am having some difficulties understanding how to parse some text from stdin to the desired variables using DCG.
Players: player1 & player2
Board : 3 moves
1A : player1
5D : player2
8Z : player1
So a game has two player variable names and then some moves by each player, I would like to have predicate that unifies Players = [player1,player2] , turn1 = [1A,8A] , turn2 = [5D].
How Would I do this using DCG ?
I have tried the following:
main :-
read_string(user_input,"\n","\r",_,FirstLine),
phrase(readPlayers(Players),FirstLine),
write(Players).
parsePlayers --> [Players].
parseColon --> [:].
parseSpace --> [ ].
readPlayers([P1,P2]) --> parsePlayers,parseColon,parseSpace,P1,parseSpace,[&], parseSpace,P2.
However this doesn't work in SWI-Prolog, how can I achieve this?

I would use library(dcg/basics), that offers some relatively low level utilities. It can be coupled with library(dcg/high_order), to further enhance your parser.
:- use_module(library(dcg/basics)).
:- use_module(library(dcg/high_order)).
player(P) -->
code(csymf,C),
codes(csym,Cs),
{atom_codes(P,[C|Cs])}.
players(Ps) -->
"Players",
sep(":"),
sequence(player,sep("&"),Ps),
blanks.
% my utilities
sep(S) --> whites, S, whites.
code(T,C) --> [C], {code_type(C,T)}.
codes(T,Cs) --> sequence(code(T),Cs).
To test the grammar you can call directly the nonterminal. Note the grammar accepts more that 2 players and correctly skips white spaces, in a flexible way.
?- phrase(players(Ps),`Players: player1 & player2& player3`).
Ps = [player1, player2, player3] ;
false.

Related

Matching part of a DFG in Prolog

I have defined a DFG grammar in Prolog which is something like this:
start --> subject, verb, object.
subject --> ([i]; [you]).
verb --> ([like]; [need]).
object --> article, noun.
article --> ([my];[your]).
noun --> ([car] ; [bike]).
Now, I would like to have a predicate that returned me the object part of a phrase accepted by this DFG.
For example, objectPart([i, like, my, car], X) should return X = [my, car].
How can I do this?
This can be done:
start(O) --> subject, verb, my_object(O).
subject --> ([i]; [you]).
verb --> ([like]; [need]).
my_object(L) --> article(A), noun(N), {L = [A,N]}.
article(A) --> ([my],{A=my};[your],{A=your}).
noun(N) --> ([car],{N=car} ; [bike],{N=bike}).
objectPart(Lst, R) :-
phrase(start(R), Lst).
Result :
?- objectPart([i, like, your, car], Z).
Z = [your, car] .
EDIT I change object in my_object because SWI-Prolog use object for XPCE.

Prolog how to eliminate left recursion

I have written the DCG (Adjective phrase and prepositional phrase) in prolog, when I tried to run it, by entering ip([every,boy,loved,some,girl]), it shows out of local stack. I realised there is something wrong with the nbar. Can someone help me out? Many thanks.
%tree
treeP(Term):-
% Print the tree assuming indentation 0
treeP(0,Term),
% Tidy up with linefeed
nl.
treeP(_N,Tree):-
% Tree is just a variable
var(Tree),!,
write(Tree).
treeP(N,[Tree|Trees]):-
proper_list([Tree|Trees]),!,
write('['),
N1 is N+1,
treePNEL(N1,[Tree|Trees]),
write(']').
treeP(N,Tree):-
% Nonatomic case
Tree=..[Functor,Argument|Arguments],
!,
% Write the functor and opening parenthesis
write(Functor),write('('),
% Set N1 to new indentation for arguments
atom_length(Functor,M), N1 is N+M+1,
% Pretty-print the arguments
treePNEL(N1,[Argument|Arguments]),
% Write right parenthesis
write(')').
treeP(_N,Tree):-
% Noncompound case
write(Tree).
treePNEL(N,[Tree1,Tree2|Trees]):-
treeP(N,Tree1),
% Go to correct position for further printing
nl, tab(N),
treePNEL(N,[Tree2|Trees]).
treePNEL(N,[Tree]):-
treeP(N,Tree).
ip(Sentence):-
setof(IP,
ip(IP,Sentence,[]),
IP),
treeP(IP).
ip(SSem) --> np(NPSem), ibar(IbarSem),
{var_replace(NPSem,NPSem1),
beta(NPSem1#IbarSem,SSem)}.
ibar(VPSem) --> i(MvdVbL),vp(VPSem,MvdVbL).
i([]) --> [].
i([]) --> [Aux],{isAux(Aux)}.
i([Verb]) --> [InflVerb],{pastInfl(Verb,InflVerb),isVerb(Verb)}.
pastInfl(see,saw).
pastInfl(love,loved).
vp(VbarSem,MvdVbL) --> vbar(VbarSem,MvdVbL).
vbar(VbarSem,MvdVbL) --> v(VSem,MvdVbL), np(NPSem),
{var_replace(VSem,VSem1),
beta(VSem1#NPSem,VbarSem)}.
v(lbd(s, lbd(x,s#lbd(y,Fla))),[]) --> [Verb],
{isVerb(Verb),Fla=..[Verb,x,y]}.
v(lbd(s,lbd(x,s#lbd(y,Fla))),[MvdVb])--> [],
{Fla=..[MvdVb,x,y]}.
np(NbarSem) --> nbar(NbarSem).
nbar(NbarSem) --> adj(AdjSem),nbar(NbarSem1),
{var_replace(AdjSem,AdjSem1),beta(AdjSem1#NbarSem1,NbarSem)}.
nbar(NbarSem) --> det(DetSem),nbar(NbarSem1),
{var_replace(DetSem,DetSem1),beta(DetSem1#NbarSem1,NbarSem)}.
nbar(NSem) --> n(NSem).
nbar(NbarSem) --> nbar(NbarSem1),pp(PPSem),
{var_replace(PPSem,PPSem1),beta(PPSem1#NbarSem1,NbarSem)}.
nbar(NSem) --> n(NSem).
pp(PPSem) --> pbar(PPSem).
pbar(NbarSem) --> po(PPSem),np(NbarSem1),
{var_replace(PPSem,PPSem1),beta(PPSem1#NbarSem1,NbarSem)}.
isVerb(love).
n(lbd(x,boy(x))) --> [boy].
n(lbd(x,girl(x))) --> [girl].
det(lbd(q,lbd(p,exists(x,(q#x & p#x))))) --> [some].
det(lbd(q,lbd(p,forall(x,(q#x -> p#x))))) --> [every].
nbar(NbarSem) --> adj(AdjSem),nbar(NbarSem1)
nbar(NbarSem) --> det(DetSem),nbar(NbarSem1)
nbar(NbarSem) --> nbar(NbarSem1),pp(PPSem)
Tabling is implemented in recent versions of SWI-Prolog. By declaring the predicates (or non-terminals) using left-recursion as tabled predicates (or non-terminals), you can keep their definitions. For details, consult:
http://www.swi-prolog.org/pldoc/man?section=tabling

Prolog logical task

There is a logical problem:
four friends: Ivan, Petr, Mikhail, Sergey spent their time in different ways: two were playing chess, one read books, one watched TV. Find who does what if Sergey does not play chess and Petr did not watch TV.
Here is my solution:
PREDICATES
question(string,string,string,string)
friend(string)
readBook(string)
watchTV(string)
playsChess(string, string)
CLAUSES
friend(ivan).
friend(petr).
friend(mikhail).
friend(sergey).
readBook(X):-
friend(X).
watchTV(X):-
friend(X),
X<>"petr".
playsChess(X,Y):-
friend(X),
friend(Y),
X<>Y,
X<>"sergey",
Y<>"sergey".
question(A,B,C,D):-
friend(A),
friend(B),
friend(C),
friend(D),
playsChess(A,B),
readBook(C),
watchTV(D),
A<>B, A<>C, A<>D,
B<>C, B<>D,
C<>D.
GOAL
question(A,B,C,D).
I have the following solution:
A=ivan, B=petr, C=mikhail, D=sergey (1)
A=ivan, B=petr, C=sergey, D=mikhail (2)
A=ivan, B=mikhail, C=petr, D=sergey (3)
A=petr, B=ivan, C=mikhail, D=sergey (4)
A=petr, B=ivan, C=sergey, D=mikhail (5)
A=petr, B=mikhail, C=ivan, D=sergey (6)
A=petr, B=mikhail, C=sergey, D=ivan (7)
A=mikhail, B=ivan, C=petr, D=sergey (8)
A=mikhail, B=petr, C=ivan, D=sergey (9)
A=mikhail, B=petr, C=sergey, D=ivan (10)
10 Solutions
But some lines are redundant since they are combined A and B. For example lines (1) and (4) (A=ivan, B=petr and A=petr, B=ivan).
I tried to use ! here:
playsChess(X,Y):-!,
friend(X),
friend(Y),
X<>Y,
X<>"sergey",
Y<>"sergey".
but it has no effect.
So the question is: how can I get rid of excess solution results?
Consider using the variable you introduce for each friend to directly represent the activity corresponding to that person:
friends([ivan=Ivan,petr=Petr,mikhail=Mikhail,sergey=Sergey]) :-
Fs0 = [Ivan,Petr,Mikhail,Sergey],
dif(Sergey, chess),
dif(Petr, tv),
select(books, Fs0, Fs1),
select(tv, Fs1, [chess,chess]).
Example query and its result:
?- friends(Fs).
Fs = [ivan=books, petr=chess, mikhail=chess, sergey=tv] ;
Fs = [ivan=chess, petr=books, mikhail=chess, sergey=tv] ;
Fs = [ivan=chess, petr=chess, mikhail=books, sergey=tv] ;
Fs = [ivan=tv, petr=chess, mikhail=chess, sergey=books] ;
Fs = [ivan=chess, petr=chess, mikhail=tv, sergey=books] ;
false.
The simplest way to solve the problem would be to constrain A and B further and force one to be "greater" than the other. I'm not sure exactly if this is the syntax in Visual Prolog, but try this. Note the use of A > B instead of A <> B.
question(A,B,C,D):-
friend(A),
friend(B),
friend(C),
friend(D),
playsChess(A,B),
readBook(C),
watchTV(D),
A > B, A<>C, A<>D,
B<>C, B<>D,
C<>D.
By constraining with > instead of <> you will ensure that you won't have symmetrical cases. For example, a > b is false, but a < b is true. However, both a <> b and b <> a are true, so the <> gives both a, b and b, a.
Your cut (!) did nothing because when you use it on a predicate that has only one clause like this:
my_predicate(...) :- !, subqueries ...
It just tells Prolog not to backtrack beyond the beginning of the first subquery. Since there are no other my_predicate clauses to backtrack to anyway, it has no effect.

DCG output single variable instead of whole clause in a list

I have a problem, while creating a question answer Prolog file. I have a database with locations and I can already get the question and write the answer out. But there are different types of objects, that require different prefixes. So I defined DCG for prefixes.
answer(P,A) :- location(P, Str, Nr),A = [there, is, article(G,K,N,P), noun(G,K,N,P), pre(P),Str,Nr].
question(A) --> questionsentence(P),{answer(P,A)}.
pre(P) --> [in, P], {member(P, [road66])}.
pre(P) --> [at, P], {member(P, [trafalgarsquare])}.
but what i get is something like this:
?-question(A, [where,is,a,kentuckys],[]).
A = [there, is, article(_G2791, _G2792, _G2793, kentuckys), noun(_G2791, _G2792, _G2793, kentuckys), prep(kentuckys), road66, 123]
This works for verifying the input properly, but it seems to be useless for the output. How can I take just the variable and not the clause?
OK, I tried to translate the whole program to a more or less usefull and working example.
location(kentuckys, road66, 121).
location(soliver, trafalgarsquare, 15).
location(marcopolo, trafalgarsquare, 15).
location(internist, jumpstreet, 21).
questionsentence(P,G) --> [where],[is], article(G), noun(G,P).
answer(P,A,G) :- location(P, Str, Nr), prep(W,Str), article(G,Art,[]), flatten([there, is, Art, P, W, Str,Nr], A).
question(A) --> questionsentence(P,G),{answer(P,A,G)}.
article(m) --> [a].
article(f) --> [an].
noun(m, P) --> [P], {member(P, [kentuckys, soliver, marcopolo])}.
noun(f, P) --> [P], {member(P, [internist])}.
prep([at],Str) :- member(Str, [trafalgarsquare, road66]).
prep([in],Str) :- member(Str, [jumpstreet]).
Result:
?- question(A, [where,is,a,kentuckys],[]).
A = [there, is, a, kentuckys, at, road66, 121] .
I think, what I looked for was a construction like: article(G,Art,[]) to determine the depending DCG variable... actually I do not fathom yet how the two last arguments are working...

String tokenization in prolog

I have the following context free grammar in a text file 'grammar.txt'
S ::= a S b
S ::= []
I'm opening this file and able to read each line in prolog.
Now i want to tokenize each line and generate a list such as
L=[['S','::=','a','S','b'],['S','::=','#']] ('#' represents empty)
How can i do this?
Write the specification in a DCG. I give you the basic (untested), you'll need to refine it.
parse_grammar([Rule|Rules]) -->
parse_rule(Rule),
parse_grammar(Rules).
parse_grammar([]) --> [].
parse_rule([NT, '::=' | Body]) -->
parse_symbol(NT),
skip_space,
"::=",
skip_space,
parse_symbols(Body),
skip_space, !. % the cut is required if you use findall/3 (see below)
parse_symbols([S|Rest]) -->
parse_symbol(S),
skip_space,
parse_symbols(Rest).
parse_symbols([]) --> [].
parse_symbol(S) -->
[C], {code_type(C, alpha), atom_codes(S, [C])}.
skip_space -->
[C], {code_type(C, space)}, skip_space.
skip_space --> [].
This parse the whole file, using this toplevel:
...,
read_file_to_codes('grammar.txt', Codes),
phrase(parse_grammar(Grammar), Codes, [])).
You say you read the file 1 line at time: then use
...
findall(R, (get_line(L), phrase(parse_rule(R), L, [])), Grammar).
HTH

Resources