Transitive function in DCG - prolog

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.

Related

Automating my pet debugging strategy in SWI-Prolog

I have a very straightforward question I'd be happy to receive any guidance on.
I'm working on a Definite Clause Grammar, and I'm running spot checks on its output. If a parse tree is confusing to me, I want to trace it back to the predicate that generated that part of the tree. So what I do is insert numeric atoms into my predicates. Like so:
sentence(sentence(Subject, Verb, Object)) --> Subject, Verb, Object.
becomes
sentence(sentence(736, Subject, Verb, Object)) --> Subject, Verb, Object.
I can then search for the number 736 and examine that particular predicate to see why it was chosen by Prolog. This has become very handy as my grammar has ballooned in size. But it's inconvenient to have to make these text edits whenever I want to debug.
Is there some elegant Prolog rule I could add to the grammar when I want to debug in this way, something that would attach a unique i.d. to each predicate?
This is highly implementation-specific, but SWI-Prolog has a source_location/2 predicate that, called inside a term_expansion/2 rule, gives you the file name and line number of the clause being expanded.
So you can use something like the following:
term_expansion(Head --> Body, EnhancedHead --> Body) :-
source_location(File, Line),
format('~w --> ~w at ~w:~w~n', [Head, Body, File, Line]),
Head =.. [Functor, Arg1 | Args],
Arg1 =.. [ArgFunctor | ArgArgs],
EnhancedArg1 =.. [ArgFunctor, File:Line | ArgArgs],
EnhancedHead =.. [Functor, EnhancedArg1 | Args].
hello -->
[world].
sentence(sentence(Subject, Verb, Object)) -->
[Subject, Verb, Object].
Note that this term_expansion/2 will print the log message for every -->/2 rule in the program:
hello --> [world] at /home/isabelle/hello.pl:9
sentence(sentence(_2976,_2978,_2980)) --> [_2976,_2978,_2980] at /home/isabelle/hello.pl:12
But it will then fail if the rule's head doesn't have at least one argument, and the first argument doesn't have at least one argument of its own. This is fine, failure just means "don't rewrite this term":
?- listing(hello).
hello([world|A], A).
true.
?- phrase(hello, Hello).
Hello = [world].
But sentence//1 will be rewritten:
?- listing(sentence).
sentence(sentence('/home/isabelle/hello.pl':12, A, B, C), [A, B, C|D], D).
true.
?- phrase(sentence(sentence(Position, S, V, O)), [isabelle, likes, prolog]).
Position = '/home/isabelle/hello.pl':12,
S = isabelle,
V = likes,
O = prolog.
You could build on this, maybe with a separate operator ---> to mark only those rules you really want rewritten. I think having this extra implicit argument is a recipe for lots of unexpected failures when you try to unify something with the actual underlying term, not the term as it appears in the source code.
So maybe a better approach would be something like this:
sentence(sentence(#position, Subject, Verb, Object)) -->
[Subject, Verb, Object].
and a corresponding term_expansion/2 rule that looks for these #position terms and replaces them accordingly.

Prolog (Sicstus) - nonmember and setof issues

Given following facts:
route(TubeLine, ListOfStations).
route(green, [a,b,c,d,e,f]).
route(blue, [g,b,c,h,i,j]).
...
I am required to find all the pairs of tube Lines that do not have any stations in common, producing the following:
| ?- disjointed_lines(Ls).
Ls = [(yellow,blue),(yellow,green),(yellow,red),(yellow,silver)] ? ;
no
I came up with the below answer, however it does not only give me incorrect answer, but it also does not apply my X^ condition - i.e. it still prints results per member of Stations lists separately:
disjointed_lines(Ls) :-
route(W, Stations1),
route(Z, Stations2),
setof(
(W,Z),X^
(member(X, Stations1),nonmember(X, Stations2)),
Ls).
This is the output that the definition produces:
| ?- disjointed_lines(L).
L = [(green,green)] ? ;
L = [(green,blue)] ? ;
L = [(green,silver)] ? ;
...
I believe that my logic relating to membership is incorrect, however I cannot figure out what is wrong. Can anyone see where am I failing?
I also read Learn Prolog Now chapter 11 on results gathering as suggested here, however it seems that I am still unable to use the ^ operator correctly. Any help would be appreciated!
UPDATE:
As suggested by user CapelliC, I changed the code into the following:
disjointed_lines(Ls) :-
setof(
(W,Z),(Stations1, Stations2)^
((route(W, Stations1),
route(Z, Stations2),notMembers(Stations1,Stations2))),
Ls).
notMembers([],_).
notMembers([H|T],L):- notMembers(T,L), nonmember(H,L).
The following, however, gives me duplicates of (X,Y) and (Y,X), but the next step will be to remove those in a separate rule. Thank you for the help!
I think you should put route/2 calls inside setof' goal, and express disjointness more clearly, so you can test it separately. About the ^ operator, it requests a variable to be universally quantified in goal scope. Maybe a concise explanation like that found at bagof/3 manual page will help...
disjointed_lines(Ls) :-
setof((W,Z), Stations1^Stations2^(
route(W, Stations1),
route(Z, Stations2),
disjoint(Stations1, Stations2)
), Ls).
disjoint(Stations1, Stations2) :-
... % could be easy as intersection(Stations1, Stations2, [])
% or something more efficient: early fail at first shared 'station'
setof/3 is easier to use if you create an auxiliary predicate that expresses the relationship you are interested in:
disjoint_routes(W, Z) :-
route(W, Stations1),
route(Z, Stations2),
disjoint(Stations1, Stations2).
With this, the definition of disjointed_lines/1 becomes shorter and simpler and no longer needs any ^ operators:
disjointed_lines(Ls) :-
setof((W, Z), disjoint_routes(W, Z), Ls).
The variables you don't want in the result of setof/3 are automatically hidden inside the auxiliary predicate definition.

Prolog build rules from atoms

I'm currently trying to to interpret user-entered strings via Prolog. I'm using code I've found on the internet, which converts a string into a list of atoms.
"Men are stupid." => [men,are,stupid,'.'] % Example
From this I would like to create a rule, which then can be used in the Prolog command-line.
% everyone is a keyword for a rule. If the list doesn't contain 'everyone'
% it's a fact.
% [men,are,stupid]
% should become ...
stupid(men).
% [everyone,who,is,stupid,is,tall]
% should become ...
tall(X) :- stupid(X).
% [everyone,who,is,not,tall,is,green]
% should become ...
green(X) :- not(tall(X)).
% Therefore, this query should return true/yes:
?- green(women).
true.
I don't need anything super fancy for this as my input will always follow a couple of rules and therefore just needs to be analyzed according to these rules.
I've been thinking about this for probably an hour now, but didn't come to anything even considerable, so I can't provide you with what I've tried so far. Can anyone push me into the right direction?
Consider using a DCG. For example:
list_clause(List, Clause) :-
phrase(clause_(Clause), List).
clause_(Fact) --> [X,are,Y], { Fact =.. [Y,X] }.
clause_(Head :- Body) --> [everyone,who,is,B,is,A],
{ Head =.. [A,X], Body =.. [B,X] }.
Examples:
?- list_clause([men,are,stupid], Clause).
Clause = stupid(men).
?- list_clause([everyone,who,is,stupid,is,tall], Clause).
Clause = tall(_G2763):-stupid(_G2763).
I leave the remaining example as an easy exercise.
You can use assertz/1 to assert such clauses dynamically:
?- List = <your list>, list_clause(List, Clause), assertz(Clause).
First of all, you could already during the tokenization step make terms instead of lists, and even directly assert rules into the database. Let's take the "men are stupid" example.
You want to write down something like:
?- assert_rule_from_sentence("Men are stupid.").
and end up with a rule of the form stupid(men).
assert_rule_from_sentence(Sentence) :-
phrase(sentence_to_database, Sentence).
sentence_to_database -->
subject(Subject), " ",
"are", " ",
object(Object), " ",
{ Rule =.. [Object, Subject],
assertz(Rule)
}.
(let's assume you know how to write the DCGs for subject and object)
This is it! Of course, your sentence_to_database//0 will need to have more clauses, or use helper clauses and predicates, but this is at least a start.
As #mat says, it is cleaner to first tokenize and then deal with the tokenized sentence. But then, it would go something like this:
tokenize_sentence(be(Subject, Object)) -->
subject(Subject), space,
be, !,
object(Object), end.
(now you also need to probably define what a space and an end of sentence is...)
be -->
"is".
be -->
"are".
assert_tokenized(be(Subject, Object)) :-
Fact =.. [Object, Subject],
assertz(Fact).
The main reason for doing it this way is that you know during the tokenization what sort of sentence you have: subject - verb - object, or subject - modifier - object - modifier etc, and you can use this information to write your assert_tokenized/1 in a more explicit way.
Definite Clause Grammars are Prolog's go-to tool for translating from strings (such as your English sentences) to Prolog terms (such as the Prolog clauses you want to generate), or the other way around. Here are two introductions I'd recommend:
http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlse29
http://www.pathwayslms.com/swipltuts/dcg/

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!

print customized result in prolog

I am working on a simple prolog program. Here is my problem.
Say I already have a fact fruit(apple).
I want the program take a input like this ?- input([what,is,apple]).
and output apple is a fruit
and for input like ?-input([is,apple,a,fruit])
instead of default print true or false, I want the program print some better phrase like yes and no
Can someone help me with this?
My code part is below:
input(Text) :-
phrase(sentence(S), Text),
perform(S).
%...
sentence(query(Q)) --> query(Q).
query(Query) -->
['is', Thing, 'a', Category],
{ Query =.. [Category, Thing]}.
% here it will print true/false, is there a way in prolog to have it print yes/no,
%like in other language: if(q){write("yes")}else{write("no")}
perform(query(Q)) :- Q.
In Prolog there is a construct if/else:
perform(query(Q)) :-
( Q
-> write(yes:Q)
; write(no)
), nl.
When I need a stricter control on output formatting, I use format.
Not very friendly, but offers most of the usual options...

Resources