I am trying to build a top left parser in prolog for the sentence "The little pigs were safe inside" and I am trying to figure out where I went wrong in my code. (Note: I'm a beginner in prolog and the code I wrote is based on a working example I had)
Can anybody point me in the right direction on this and maybe shine some light on it?
Code:
% The little pigs were safe inside.
% ------------------------------------------------ TERMINALS ------------------------------------------------
leaf(determiner) --> [the].
leaf(adjective) --> [little].
leaf(adjective) --> [safe].
leaf(noun) --> [pigs].
leaf(verb) --> [were].
leaf(adverb) --> [inside].
% ------------------------------------------------ NON-TERMINALS ------------------------------------------------
lcd(noun_phrase,sentence):-!.
lcd(determiner,noun_phrase):-!.
lcd(adjective,adjective_phrase):-!.
lcd(adverb,adjective_phrase):-!.
lcd(verb,verb_phrase):-!.
lc(X,X):-!.
lc(X,Y):-lcd(X,Y),!.
lc(X,Y):-lcd(X,Z),lc(Z,Y).
% ------------------------------------------------ RULES ------------------------------------------------
parse(Nterm,As,[W0|W1],Wn):-
leaf(Pterm,[W0|W1],W1),
lc(Pterm,Nterm),
Ap=..[Pterm,W0],
P=..[Pterm,Nterm,Ap,As,W1,Wn],
call(P).
noun_phrase(Nt,NP,As)-->{lc(sentence,Nt)},parse(verb_phrase, VP),sentence(Nt,sentence(NP,VP),As),!.
noun_phrase(noun_phrase,E,E)-->[].
determiner(Nt,D,As)-->{lc(noun_phrase,Nt)},parse(adjective_phrase,N),noun_phrase(Nt,noun_phrase(D,N),As).
adjective(Nt,A,As)-->{lc(adjective_phrase,Nt)},parse(adjective_phrase,N),adjective_phrase(Nt,adjective_phrase(A,N),As).
adverb(Nt,A,As)-->{lc(adjective_phrase,Nt)},parse(adjective_phrase,N),adjective_phrase(Nt,adjective_phrase(A,N),As).
noun(Nt,N,As)-->{lc(adjective_phrase,Nt)},adjective_phrase(Nt,adjective_phrase(N),As).
adjective_phrase(adjective_phrase,A,A)-->[].
verb(Nt,V,As)-->{lc(verb_phrase,Nt)},parse(noun_phrase,N),verb_phrase(Nt,verb_phrase(V,N),As).
verb(Nt,V,As)-->{lc(verb_phrase,Nt)},verb_phrase(Nt,verb_phrase(V),As).
verb_phrase(verb_phrase,A,A)-->[].
sentence(s,A,A)-->[].
test(S,A):-parse(S,A,[the, little, pigs, were, safe, inside],[]).
Test trace:
trace,test(S,A).
Call: (9) test(_4648, _4650) ? creep
Call: (10) parse(s, _4650, [the, little, pigs, were, safe, inside], []) ? creep
Call: (11) leaf(_5024, [the, little, pigs, were, safe, inside], [little, pigs, were, safe, inside]) ? creep
Exit: (11) leaf(determiner, [the, little, pigs, were, safe, inside], [little, pigs, were, safe, inside]) ? creep
Call: (11) lc(determiner, s) ? creep
Call: (12) lcd(determiner, s) ? creep
Fail: (12) lcd(determiner, s) ? creep
Redo: (11) lc(determiner, s) ? creep
Call: (12) lcd(determiner, _5026) ? creep
Exit: (12) lcd(determiner, noun_phrase) ? creep
Call: (12) lc(noun_phrase, s) ? creep
Call: (13) lcd(noun_phrase, s) ? creep
Fail: (13) lcd(noun_phrase, s) ? creep
Redo: (12) lc(noun_phrase, s) ? creep
Call: (13) lcd(noun_phrase, _5026) ? creep
Exit: (13) lcd(noun_phrase, sentence) ? creep
Call: (13) lc(sentence, s) ? creep
Call: (14) lcd(sentence, s) ? creep
Fail: (14) lcd(sentence, s) ? creep
Redo: (13) lc(sentence, s) ? creep
Call: (14) lcd(sentence, _5026) ? creep
Fail: (14) lcd(sentence, _5026) ? creep
Fail: (13) lc(sentence, s) ? creep
Fail: (12) lc(noun_phrase, s) ? creep
Fail: (11) lc(determiner, s) ? creep
Redo: (11) leaf(_5024, [the, little, pigs, were, safe, inside], [little, pigs, were, safe, inside]) ? creep
Fail: (11) leaf(_5024, [the, little, pigs, were, safe, inside], [little, pigs, were, safe, inside]) ? creep
Fail: (10) parse(s, _4650, [the, little, pigs, were, safe, inside], []) ? creep
Fail: (9) test(_4648, _4650) ? creep
false.
The expected output for this grammar when running the test should be something like:
S = [the, little, pigs, were, safe, inside],A = s(np(d(the), adjp(adj(little), n(pigs))), vp(v(were), adjp(adj(safe), adv(inside)))) .
For anyone who might need this later on.
Only a few fixes were needed to make this work. Compare the two programs to find the mistakes :)
Solution
% The little pigs were safe inside.
% ------------------------------------------------ TERMINALS ------------------------------------------------
leaf(determiner) --> [the].
leaf(adjective) --> [little].
leaf(adjective) --> [safe].
leaf(noun) --> [pigs].
leaf(verb) --> [were].
leaf(adverb) --> [inside].
% ------------------------------------------------ NON-TERMINALS ------------------------------------------------
lcd(noun_phrase,sentence):-!.
lcd(determiner,noun_phrase):-!.
lcd(verb,verb_phrase):-!.
lcd(adjective,adjective_phrase):-!.
lc(X,X):-!.
lc(X,Y):-lcd(X,Y),!.
lc(X,Y):-lcd(X,Z),lc(Z,Y).
parse(Nterm,As,[W0|W1],Wn):-
leaf(Pterm,[W0|W1],W1),
lc(Pterm,Nterm),
Ap=..[Pterm,W0],
P=..[Pterm,Nterm,Ap,As,W1,Wn],
call(P).
% ------------------------------------------------ RULES ------------------------------------------------
noun_phrase(Nt,NP,As)-->{lc(sentence,Nt)},parse(verb_phrase, VP),sentence(Nt,sentence(NP,VP),As),!.
noun_phrase(noun_phrase,E,E)-->[].
determiner(Nt,D,As)-->{lc(noun_phrase,Nt)},parse(adjective_phrase,N),noun_phrase(Nt,noun_phrase(D,N),As).
adjective_phrase(adjective_phrase,A,A)-->[].
verb(Nt,V,As)-->{lc(verb_phrase,Nt)},parse(adjective_phrase,N),verb_phrase(Nt,verb_phrase(V,N),As).
verb_phrase(verb_phrase,A,A)-->[].
adjective(Nt,A,As)-->{lc(adjective_phrase,Nt)},parse(noun,N),adjective_phrase(Nt,adjective_phrase(A,N),As).
noun(noun,A,A)-->[].
adjective(Nt,A,As)-->{lc(adjective_phrase,Nt)},parse(adverb,Adv),adjective_phrase(Nt,adjective_phrase(A,Adv),As).
adverb(adverb,A,A)-->[].
sentence(sentence,A,A)-->[].
% ------------------------------------------------ TEST ------------------------------------------------
test(sentence,A):-parse(sentence,A,[the, little, pigs, were, safe, inside],[]).
test1(sentence,A):-parse(sentence,A,[the, little, pigs],[]).
predicates
nondeterm s(integer,integer)
nondeterm p(integer,integer,integer)
clauses
s(V,R) :-
p(0,V,R).
%,write(R),nl.
p(R,0,R).
p(Inc,V,R) :-
I2=Inc+V,
N1=V-1,
p(I2,N1,R).
goal
s(9,O).
gives an arithmetic overflow,,,why??
In Prolog mathematical expressions are not done with assignment, e.g. =. Prolog does not use assignment like many common programming languages, Prolog uses unification. If you want to do math expressions in Prolog and unify the result with a variable then you need to use the is/2 operator
I2 is Inc+V
N1 is V-1
You also need a guard statement to keep the second clause from being executed if the second parameter is 0.
s(V,O) :-
p(0,V,O).
p(R,0,R).
p(Inc,V,R) :-
V \= 0,
I2 is Inc+V,
N1 is V-1,
p(I2,N1,R).
Now your query returns
?- s(9,O).
O = 45 ;
false.
Complementing Guy's answer, it is instructive to run your query in the Prolog tracer as it clearly shows that, because you used unification (=/2) instead of arithmetic expression evaluation (is/2), your query build an increasingly bigger compound term at each recursive call until the global stack space is exhausted:
[trace] ?- s(9,O).
Call: (8) s(9, _3176) ? creep
Call: (9) p(0, 9, _3176) ? creep
Call: (10) _3396=0+9 ? creep
Exit: (10) 0+9=0+9 ? creep
Call: (10) _3402=9-1 ? creep
Exit: (10) 9-1=9-1 ? creep
Call: (10) p(0+9, 9-1, _3176) ? creep
Call: (11) _3408=0+9+(9-1) ? creep
Exit: (11) 0+9+(9-1)=0+9+(9-1) ? creep
Call: (11) _3414=9-1-1 ? creep
Exit: (11) 9-1-1=9-1-1 ? creep
Call: (11) p(0+9+(9-1), 9-1-1, _3176) ? creep
Call: (12) _3420=0+9+(9-1)+(9-1-1) ? creep
Exit: (12) 0+9+(9-1)+(9-1-1)=0+9+(9-1)+(9-1-1) ? creep
Call: (12) _3426=9-1-1-1 ?
...
This is the knowledge database
student(jack,100,21,m).
takes(100,cs01).
takes(100,cs02).
takes(100,cs03).
teaches(doe,cs01).
course(cs01,ai).
course(cs02,cpp).
course(cs03,java).
isTaughtBy(Sname,Lname) :-
teaches(Lname,Mcode),
student(Sname,Scode,_,_),
takes(Scode,Mcode).
When running isTaughtBy(jack,doe) it returns true (like its supposed to) and false (for some reason, probably because jack takes multiple modules).
This is the trace:
[trace] ?- isTaughtBy(jack,doe).
Call: (8) isTaughtBy(jack, doe) ? creep
Call: (9) teaches(doe, _18526) ? creep
Exit: (9) teaches(doe, cs01) ? creep
Call: (9) student(jack, _18526, _18528, _18530) ? creep
Exit: (9) student(jack, 100, 21, m) ? creep
Call: (9) takes(100, cs01) ? creep
Exit: (9) takes(100, cs01) ? creep
Exit: (8) isTaughtBy(jack, doe) ? creep
true ;
Redo: (9) takes(100, cs01) ? creep
Fail: (9) takes(100, cs01) ? creep
Fail: (8) isTaughtBy(jack, doe) ? creep
false.
Why is it redoing takes(100,cs01) if it was already checked above? Why is it returning false even though its clearly defined in the database? What am i not understanding here? I just want it to return true or false if a student is taught by a lecturer on any of the modules they are taking.
I am trying to build a program that takes two integers (for example, 4 and 15) and returns the multiples of the first integer that divide into the second integer.
My program is as follows:
divisible(D,U,X):-
divisible_ext(D,U,D,X).
divisible_ext(D,U,D,X):-
U < D,
!.
divisible_ext(D,U,S,X):-
U > D,
D1 is D + S,
divisible_ext(D1,U,S,X1),
X is D.
As far as I am aware, my program should fail the base case with each call until the D value is greater than U (so with 4 and 15, 16 > 15). However in the trace, I can see that the base case is only called the first time, and then never again. Thus when D = 16, the U > D call fails and the entire program fails.
Why is the base case only being called once? Is there something I am not understanding about Prolog that I need to know, or is there a change to my code that I should make?
Edit: Here is my trace:
[trace] 20 ?- divisible(4,15,X).
Call: (7) divisible(4, 15, _G9543) ? creep
Call: (8) divisible_ext(4, 15, 4, _G9543) ? creep
Call: (9) 15<4 ? creep
Fail: (9) 15<4 ? creep
Redo: (8) divisible_ext(4, 15, 4, _G9543) ? creep
Call: (9) 15>4 ? creep
Exit: (9) 15>4 ? creep
Call: (9) _G9622 is 4+4 ? creep
Exit: (9) 8 is 4+4 ? creep
Call: (9) divisible_ext(8, 15, 4, _G9625) ? creep
Call: (10) 15>8 ? creep
Exit: (10) 15>8 ? creep
Call: (10) _G9625 is 8+4 ? creep
Exit: (10) 12 is 8+4 ? creep
Call: (10) divisible_ext(12, 15, 4, _G9628) ? creep
Call: (11) 15>12 ? creep
Exit: (11) 15>12 ? creep
Call: (11) _G9628 is 12+4 ? creep
Exit: (11) 16 is 12+4 ? creep
Call: (11) divisible_ext(16, 15, 4, _G9631) ? creep
Call: (12) 15>16 ? creep
Fail: (12) 15>16 ? creep
Fail: (11) divisible_ext(16, 15, 4, _G9631) ? creep
Fail: (10) divisible_ext(12, 15, 4, _G9628) ? creep
Fail: (9) divisible_ext(8, 15, 4, _G9625) ? creep
Fail: (8) divisible_ext(4, 15, 4, _G9543) ? creep
Fail: (7) divisible(4, 15, _G9543) ? creep
false.
Why is the base case only being called once?
The base case is
divisible_ext(D,U,D,X) :-
and the other case is
divisible_ext(D,U,S,X) :-
Notice that on the first call
Call: (8) divisible_ext(4, 15, 4, _G9543) ? creep
divisible_ext(D, U, D, X) :- <-- Base case
divisible_ext(D, U, S, X) :- <-- Other case
For the base case D = 4 for both D and
for the other case D = 4 and S = 4
so both predicates can be called.
Notice on the second call
Call: (9) divisible_ext(8, 15, 4, _G9625) ? creep
divisible_ext(D, U, D, X) :- <-- Base case
divisible_ext(D, U, S, X) :- <-- Other case
For the base case D = 8 and D = 4 and
for the other case D = 4 and S = 4
so the base can not be called because the first D is now 8 and second D is 4 which means the unification will not work and thus the predicate can not be called.
Write a rule that take a list whose elements are themselves lists and
print on each line the elements of internals list:
Example:
?- printList[[1,a],[2,b]]).
1 a
2 b
The solution it the following one:
/* BASE CASE: The list is empty, so there is nothing to print */
printList([]).
printList([P|R]):- printList(P),
!,
nl,
printList(R).
printList([X|R]):- write(X),
!,
printList(R).
I have the printList rule that reaches the base case when the list is empty and in this case there is nothing to print.
If I am not in the base case (the list is not empty) it calls the second rule printList([P|R]) and now I have my first doubt:
The element P is a list because Prolog automatically handles an internal list as an element?
So, If I have something like:
[[1,a],[2,b],[3,c],[4,d]] I have that Prolog automatically match in this way:
P = [1,a] (the first list as the head element)
R = [[2,b],[3,c],[4,d]] (the other 3 list are the element of a tail list)
And then the program calls the printList predicate on the head element (the first list) and this version of the rule writes all the elements in the current list.
Is this right this interpretation?
Now I have some doubts about about the trace of this program, for example if I execute this statement I obtain the following trace:
[trace] ?- printList([[1,a], [2,b]]).
Call: (6) printList([[1, a], [2, b]]) ? creep
Call: (7) printList([1, a]) ? creep
Call: (8) printList(1) ? creep
Fail: (8) printList(1) ? creep
Redo: (7) printList([1, a]) ? creep
Call: (8) write(1) ? creep
1
Exit: (8) write(1) ? creep
Call: (8) printList([a]) ? creep
Call: (9) printList(a) ? creep
Fail: (9) printList(a) ? creep
Redo: (8) printList([a]) ? creep
Call: (9) write(a) ? creep
a
Exit: (9) write(a) ? creep
Call: (9) printList([]) ? creep
Exit: (9) printList([]) ? creep
Exit: (8) printList([a]) ? creep
Exit: (7) printList([1, a]) ? creep
Call: (7) nl ? creep
Exit: (7) nl ? creep
Call: (7) printList([[2, b]]) ? creep
Call: (8) printList([2, b]) ? creep
Call: (9) printList(2) ? creep
Fail: (9) printList(2) ? creep
Redo: (8) printList([2, b]) ? creep
Call: (9) write(2) ? creep
2
Exit: (9) write(2) ? creep
Call: (9) printList([b]) ? creep
Call: (10) printList(b) ? creep
Fail: (10) printList(b) ? creep
Redo: (9) printList([b]) ? creep
Call: (10) write(b) ? creep
b
Exit: (10) write(b) ? creep
Call: (10) printList([]) ? creep
Exit: (10) printList([]) ? creep
Exit: (9) printList([b]) ? creep
Exit: (8) printList([2, b]) ? creep
Call: (8) nl ? creep
Exit: (8) nl ? creep
Call: (8) printList([]) ? creep
Exit: (8) printList([]) ? creep
Exit: (7) printList([[2, b]]) ? creep
Exit: (6) printList([[1, a], [2, b]]) ? creep
true.
This is quite clear for me (I think that my previous reasoning is right) but I am not understanding why whenever it reaches an element in an internal list it calls the printList relation on it (that is a simple element and not a list), for example here:
Call: (8) printList(1) ? creep
Fail: (8) printList(1) ? creep
the program had considered the first list of the original list and then, into it to have to print its first element, why call the printList relation on this simple element
Is it because this simple element may in turn be internal lists?
Something like:
[[[1.1,a1,a2],[1.2,b1,b2]], [2,b]] (in which I have a list that contains 2 lists and the first element it is a list that contains 2 lists. So the program checks if an element it is an element or an internal list?
I think you're over-thinking it. Look at the code:
printList([P|R]):- printList(P),
Right there you can see that printList/1 is being unified with the head of the list. The fact that all the rules of printList/1 match lists and only lists is a fact that you, the human, can immediately see. But Prolog does not "notice" this fact, so if you are to call, say,
printList([1])
the first matching rule is the one above, so it will immediately try to unify printList(1). This will fail, naturally, because 1 is not a list and so doesn't match any of the rules for printList/1. Prolog then backtracks and tries the next rule, which is the one that starts like this:
printList([X|R]):- write(X),
This is clearly going to unify [1] with X = 1, R = [], so it's clearly going to write the first element, the one, and then proceed as usual. There is no magic here involving "internal lists," which as far as I'm aware is not a concept in Prolog at all (if such a thing is treated in the compiler it is well hidden from the user of Prolog).
Prolog isn't psychic; it has to try the rules to see if they fail, even if that attempt is essentially a failing pattern-match in the head of the Horn clause.
I am unable to distinguish your first from your second question so I hope this answers both. :)