Writing a simple "process of elimination" Prolog code using DCGs - prolog

I have simplified a more complex problem to the following: there are three houses on a street with three different colours (no colour repeated); red, blue, green. Write a program using DCGs to simulate all permutations/possibilities. My code won't run and I'm struggling to see why. Any corrections would really help.
s --> h(X), h(Y), h(Z), X\=Y, X\=Z, Y\=Z.
h(X) --> Col(X).
Col(X) --> [red].
Col(X) --> [blue].
Col(X) --> [green].

s/Col/col/
And then, you are using within s//0 Prolog goals in the place of non-terminals. That does not work, you need to "escape" them with {}//0 like so
s -->h(X),h(Y),h(Z),{X\=Y,X\=Z,Y\=Z}.
But I would rather write:
s --> {dif(X,Y), dif(Y,Z), dif(X,Z)}, h(X),h(Y),h(Z).
In this manner Prolog performs all the bookkeeping for you.
If we're at it. Don't forget to call the non-terminal via phrase/2. Thus:
?- phrase(s, L).

You are (also) forgetting to 'return' the value from the leaves:
...
col(red)-->[red].
...
With a so small dataset, it's tempting to hardcode the permutation:
s --> r,g,b ; r,b,g ; g,r,b ; b,r,g ; g,b,r ; b,g,r.
r --> [red].
g --> [green].
b --> [blue].

Related

Transitive function in DCG

Is it possible to make a transitive function like the following in DCG? Or to combine it with a DCG rule?
genx(A,B) :- gen(A,B).
genx(A,C) :- gen(A,B), genx(B,C).
gen(a,b).
gen(b,c).
I will explain what i'm trying to do exactly :
If i have this grammar:
noun_phrase(D,N) --> det(D), noun(N).
noun(n(cat)) --> [cat].
I want to make some restriction like if i want N in noun(N) to be an animal. So i can use something like this:
noun_phrase(np(D,N)) --> det(D), noun(N), genx(N, animal).
Where the information of a cat is an animal is inferenced from some facts like:
gen(cat,pet).
gen(pet,animal).
Thanks
Not sure to undestand.
If I'm not wrong, from the formal point of view the rules
genx(A,B) :- gen(A,B).
genx(A,C) :- gen(A,B), genx(B,C).
can be written in DCG syntax as
genx --> gen.
genx --> gen, genx.
and, with facts,
gen(a, b).
gen(b, c).
genx(a, c) should return true.
However, the A, B, C in DCG are intended to be list.
I don't know if is reasonable to use DCG (that is intended for parsing) in this way to implement algebrical rules.

Tokenizing a string in Prolog using DCG

Let's say I want to tokenize a string of words (symbols) and numbers separated by whitespaces. For example, the expected result of tokenizing "aa 11" would be [tkSym("aa"), tkNum(11)].
My first attempt was the code below:
whitespace --> [Ws], { code_type(Ws, space) }, whitespace.
whitespace --> [].
letter(Let) --> [Let], { code_type(Let, alpha) }.
symbol([Sym|T]) --> letter(Sym), symbol(T).
symbol([Sym]) --> letter(Sym).
digit(Dg) --> [Dg], { code_type(Dg, digit) }.
digits([Dg|Dgs]) --> digit(Dg), digits(Dgs).
digits([Dg]) --> digit(Dg).
token(tkSym(Token)) --> symbol(Token).
token(tkNum(Token)) --> digits(Digits), { number_chars(Token, Digits) }.
tokenize([Token|Tokens]) --> whitespace, token(Token), tokenize(Tokens).
tokenize([]) --> whitespace, [].
Calling tokenize on "aa bb" leaves me with several possible responses:
?- tokenize(X, "aa bb", []).
X = [tkSym([97|97]), tkSym([98|98])] ;
X = [tkSym([97|97]), tkSym(98), tkSym(98)] ;
X = [tkSym(97), tkSym(97), tkSym([98|98])] ;
X = [tkSym(97), tkSym(97), tkSym(98), tkSym(98)] ;
false.
In this case, however, it seems appropriate to expect only one correct answer. Here's another, more deterministic approach:
whitespace --> [Space], { char_type(Space, space) }, whitespace.
whitespace --> [].
symbol([Sym|T]) --> letter(Sym), !, symbol(T).
symbol([]) --> [].
letter(Let) --> [Let], { code_type(Let, alpha) }.
% similarly for numbers
token(tkSym(Token)) --> symbol(Token).
tokenize([Token|Tokens]) --> whitespace, token(Token), !, tokenize(Tokens).
tokenize([]) --> whiteSpace, [].
But there is a problem: although the single answer to token called on "aa" is now a nice list, the tokenize predicate ends up in an infinite recursion:
?- token(X, "aa", []).
X = tkSym([97, 97]).
?- tokenize(X, "aa", []).
ERROR: Out of global stack
What am I missing? How is the problem usually solved in Prolog?
The underlying problem is that in your second version, token//1 also succeeds for the "empty" token:
?- phrase(token(T), "").
T = tkSym([]).
Therefore, unintentionally, the following succeeds too, as does an arbitrary number of tokens:
?- phrase((token(T1),token(T2)), "").
T1 = T2, T2 = tkSym([]).
To fix this, I recommend you adjust the definitions so that a token must consist of at least one lexical element, as is also typical. A good way to ensure that at least one element is described is to split the DCG rules into two sets. For example, shown for symbol///1:
symbol([L|Ls]) --> letter(L), symbol_r(Ls).
symbol_r([L|Ls]) --> letter(L), symbol_r(Ls).
symbol_r([]) --> [].
This way, you avoid an unbounded recursion that can endlessly consume empty tokens.
Other points:
Always use phrase/2 to access DCGs in a portable way, i.e., independent of the actual implementation method used by any particular Prolog system.
The [] in the final DCG clause is superfluous, you can simply remove it.
Also, avoid using so many !/0. It is OK to commit to the first matching tokenization, but do it only at a single place, like via a once/1 wrapped around the phrase/2 call.
For naming, see my comment above. I recommend to use tokens//1 to make this more declarative. Sample queries, using the above definition of symbol//1:
?- phrase(tokens(Ts), "").
Ts = [].
?- phrase(tokens(Ls), "a").
Ls = [tkSym([97])].
?- phrase(tokens(Ls), "a b").
Ls = [tkSym([97]), tkSym([98])].

Construct clause step by step

I would like to construct a clause after a series of steps. For instance, if i verify a condition then i assert a part of a clause. If "the pen is red" i obtain:
color(pen, red)
if "the pen is on the table":
on(pen, table)
if "the table is blue":
color(table, blue)
At the end I have to get:
color(pen, red), on(pen, table), color(table,blue).
I would like to insert the final clause in an external file. How can I do?
EDIT:
I insert a text similar to the above and deduct these separate predicate:
first color(pen,red), second on(pen,table), third color(table,blue)
I would like to obtain a clause that is :
text(t1):- color(pen, red), on(pen, table), color(table,blue).
and this clause must be inserted in a file.
INPUT: single predicate.
OUTPUT: one clause with all predicates.
I'd attack the problem with DCGs.
sentence(S) --> color_statement(S) ; on_statement(S).
det --> [a].
det --> [the].
color_statement(color(Noun, Color)) --> det, [Noun], [is], color(Color).
color(Color) --> [Color], { color(Color) }.
color(red). color(blue).
on_statement(on(Noun, Place)) --> det, [Noun], [is,on], det, [Place].
This is assuming you have some kind of tokenization in place, but for demo purposes, you'll find this "works":
?- phrase(sentence(S), [the,pen,is,on,the,bookshelf]).
S = on(pen, bookshelf).
You will no doubt need to extend these rules for your purposes. You can find tokenization stuff by searching, and only you know exactly the kinds of nouns and modifiers you want to support, so this is really just a sketch of how this could proceed.
From here you're going to create another rule to handle multiple statements.
clause([]) --> [].
clause([S|Rest]) --> sentence(S), ['.'], clause(Rest).
Testing it works like so:
?- phrase(clause(S), [the,pen,is,on,the,bookshelf,'.',the,pen,is,red,'.']).
S = [on(pen, bookshelf), color(pen, red)]
So these are the clauses you want. Now you just need a predicate to bring them together.
list_and([X,Y], (X,Y)).
list_and([X|Xs], (X,Rest)) :- list_and(Xs, Rest).
clause_for(Name, Tokens, Predicate) :-
phrase(clause(Parts), Tokens),
list_and(Parts, AndSequence),
Predicate = (Name :- AndSequence).
This does basically what you want, but you need to furnish a name for your predicate:
?- clause_for(bob, [the,pen,is,on,the,bookshelf,'.',the,pen,is,red,'.'], P).
P = (bob:-on(pen, bookshelf), color(pen, red))
Hope this helps!

Write a Prolog DCG grammar that handle the mean of a sentence and also build its parse tree

I have this DCG grammar that understand and agree phrases like: [john, paints] and [john, likes, mary] managing the semantic meaning directly into the DCG grammar by the use of parameters
sentence2(VP) --> noun_phrase2(Actor),
verb_phrase2(Actor, VP).
noun_phrase2(Name) --> properName(Name).
verb_phrase2(Actor, VP) --> intrans_verb(Actor, VP).
verb_phrase2(Somebody, VP) --> trans_verb(Somebody, Something, VP),
noun_phrase2(Something).
properName(john) --> [john].
properName(mary) --> [mary].
intrans_verb(Actor, paints(Actor)) --> [paints].
trans_verb(Somebody, Something, likes(Somebody, Something)) --> [likes].
For example the mean of the phrase [john, paints] will be: paints(john), infact this is the result of the query:
?- sentence2(Meaning, [john,paints],[]).
Meaning = paints(john)
Ok, so this handle the meaning without build a parse tree.
I have an exercise that ask me to modify the previous grammar to obtain the mean from the syntattic tree of my sentence. So my queries have to return the parse tree, and also the meaning of the sentence
But I am finding some problem doing it...I was trying something like this, but don't work:
/** Adding the meaning into the Parse Tree: */
sentence2(sentence(Name, VerbPhrase)) --> noun_phrase2(Name),
verb_phrase2(VerbPhrase).
noun_phrase2(noun_phrase(Name)) --> properName2(Name).
verb_phrase2(verb_phrase(IntransVerb)) --> intrans_verb2(IntransVerb).
verb_phrase2(verb_phras(TransVerb, ProperName)) --> trans_verb2(TransVerb),
noun_phrase2(ProperName).
/* properName, intrans_verb ant trans_verb are LEAVES: */
properName2(properName(john)) --> [john].
properName2(properName(mary)) --> [mary].
intrans_verb2(Actor, intrans_verb2(paints(Actor))) --> [paints].
trans_verb2(Somebody, Something, trans_verb2(likes(Somebody, Something))) --> [likes].
I think your question is ill-posed. If you say
?- sentence2(Meaning, [john,paints], []).
Meaning = paints(john).
you're clearly saying that the result of the parse is a "meaning" and not a parse tree. I would expect a parse tree to look more like this:
Parse = s(np(properNoun(john)), vp(intrans(paints))).
You can easily produce parse trees by augmenting your DCG with some structural information:
sentence(s(NounPhrase, VerbPhrase)) -->
noun_phrase(NounPhrase),
verb_phrase(VerbPhrase).
noun_phrase(proper_noun(john)) --> [john].
verb_phrase(intransitive(paints)) --> [paints].
If you want one or the other, just generate the one you want. If you want both, you should probably collect the meaning after the parse using the tree. Otherwise there's not much point to getting a parse tree, is there? Here's a sketch:
meaning(s(proper_noun(Noun), intransitive(Verb)), Meaning) :-
Meaning =.. [Verb, Noun].
This would of course have to be made more robust, but this is how it might be used:
?- phrase(sentence(S), [john, paints]), meaning(S, Meaning).
S = s(proper_noun(john), intransitive(paints)),
Meaning = paints(john).
Now explore, play! Make something that parses some of your native language (Italian, right?) into "meaningful" structures. Parse a few sentences of Turkish into "meaning" and generate Italian from it. You'll be surprised how easily it all comes together.

Parsing numbers with multiple digits in Prolog

I have the following simple expression parser:
expr(+(T,E))-->term(T),"+",expr(E).
expr(T)-->term(T).
term(*(F,T))-->factor(F),"*",term(T).
term(F)-->factor(F).
factor(N)-->nat(N).
factor(E)-->"(",expr(E),")".
nat(0)-->"0".
nat(1)-->"1".
nat(2)-->"2".
nat(3)-->"3".
nat(4)-->"4".
nat(5)-->"5".
nat(6)-->"6".
nat(7)-->"7".
nat(8)-->"8".
nat(9)-->"9".
However this only supports 1-digit numbers. How can I parse numbers with multiple digits in this case?
Use accumulator variables, and pass those in recursive calls. In the following, A and A1 are the accumulator.
digit(0) --> "0".
digit(1) --> "1".
% ...
digit(9) --> "9".
nat(N) --> digit(D), nat(D,N).
nat(N,N) --> [].
nat(A,N) --> digit(D), { A1 is A*10 + D }, nat(A1,N).
Note that the first nat clause initializes the accumulator by consuming a digit, because you don't want to match the empty string.
nat(0).
nat(N):-nat(N-1).
But you use a syntax that I don't know (see my comment above).
Can you provide a sample input?
I think this might work:
nat(N)-->number(N).
If that fails try:
nat(N)-->number(N),!.
The ! is a cut it stops the unification. You can read about it in books/tutorials.

Resources