Prolog: Sentence Parser - prolog

Been sat here for hours now just staring at this code and have no idea what I'm doing wrong. I know what's happening from tracing the code through (it is going on an eternal loop when it hits verbPhrase). Any tips are more then welcome. Thank you.
% Knowledge-base
det(the).
det(a).
adjective(quick).
adjective(brown).
adjective(orange).
adjective(sweet).
noun(cat).
noun(mat).
noun(fox).
noun(cucumber).
noun(saw).
noun(mother).
noun(father).
noun(family).
noun(depression).
prep(on).
prep(with).
verb(sat).
verb(nibbled).
verb(ran).
verb(looked).
verb(is).
verb(has).
% Sentece Structures
sentence(Phrase) :-
append(NounPhrase, VerbPhrase, Phrase),
nounPhrase(NounPhrase),
verbPhrase(VerbPhrase).
sentence(Phrase) :-
verbPhrase(Phrase).
nounPhrase([]).
nounPhrase([Head | Tail]) :-
det(Head),
nounPhrase2(Tail).
nounPhrase(Phrase) :-
nounPhrase2(Phrase).
nounPhrase(Phrase) :-
append(NP, PP, Phrase),
nounPhrase(NP),
prepPhrase(PP).
nounPhrase2([]).
nounPhrase2(Word) :-
noun(Word).
nounPhrase2([Head | Tail]) :-
adjective(Head),
nounPhrase2(Tail).
prepPhrase([]).
prepPhrase([Head | Tail]) :-
prep(Head),
nounPhrase(Tail).
verbPhrase([]).
verbPhrase(Word) :-
verb(Word).
verbPhrase([Head | Tail]) :-
verb(Head),
nounPhrase(Tail).
verbPhrase(Phrase) :-
append(VP, PP, Phrase),
verbPhrase(VP),
prepPhrase(PP).

I figured it out now after a bit of trolling the internet, so will answer it here if anyone else struggles with it.
The problem was that the append was creating an empty list. This list was passed as a parameter, then split again into two empty lists. And this was repeated over and over again. To stop this, everytime the append function is used, there must be a check if the lists are empty.
For example
verbPhrase(Phrase):-
append(VP, PP, Phrase),
VP \= [],
PP \= [],
verbPhrase(VP),
prepPhrase(PP).

Related

How to print a list of pairs?

Nobody cares to answer my very important long question so I keep it short.
% https://stackoverflow.com/questions/29230608/swi-prolog-print-multiple-variables
pretty_row(Ls) :- maplist(format, Ls).
uci(w-k, 'K').
uci(b-q, 'q').
ls([w-k, b-q]).
?- ls(L), pretty_row(L).
% Expected output
Kq
% Prolog
pretty_row(Ls) :- maplist(format, Ls).
uci(w-k, 'K').
uci(b-q, 'q').
ls([w-k, b-q]).
ucis([], []).
ucis([P|Rest], [Z|ZRest]) :- uci(P, Z), ucis(Rest, ZRest).
I am not sure if there is a built in predicate that does what ucis do.

How to delete a given element X from the list in prolog [duplicate]

This question already has answers here:
Deleting all occurrences of an element from a list
(4 answers)
Closed 2 years ago.
I want to delete a given element X from the list in Prolog. Such that delete(X,L) deletes the first instance (from the head) of integer X from list L.
The predicate should be of the form delete(X,List).
I don't know how to do it.
For example:
delete(5,[2,3,4,5,6,7,8,9]).
Should return the list with 5 removed from it
List=[2,3,4,6,7,8,9]
Any help is much appreciated.
Thank you
Better with green cuts then. And test cases are always mandatory.
deleted(X, [H|L1], [H|L2]) :- X\=H, !, deleted(X,L1,L2).
deleted(X, [X|L1], L2) :- !, deleted(X,L1,L2).
deleted(_, [], []).
:- begin_tests(deleted).
test(empty) :- deleted(1,[],[]).
test(not_exists) :- deleted(1,[2,3,4,5,6],R), R = [2,3,4,5,6].
test(exists_once) :- deleted(1,[2,1,4,5,6],R), R = [2,4,5,6].
test(exists_once_end) :- deleted(1,[2,3,4,5,1],R), R = [2,3,4,5].
test(exists_multi) :- deleted(1,[2,1,4,1,6],R), R = [2,4,6].
test(exists_only) :- deleted(1,[1,1,1,1,1],R), R = [].
:- end_tests(deleted).
rt :- run_tests(deleted).
?- rt.
% PL-Unit: deleted ...... done
% All 6 tests passed
true.
Sadly this doesn't run in "reverse"
?- deleted(1,X,[2,3]).
blows the stack sky-high ... instead returning an infinite series of possible X, like [1,2,3] etc.
What does one need to change to make it behave? (I think it's not directly evident and may demand another approach).
Addendum: Green cuts removed
Yep, it still works (although having cuts is essential to keep the machine from getting bogged down in keeping avenues open that we know (as programmers who prove theorems in our head as we write code) are useless:
deleted(X, [H|L1], [H|L2]) :- X\=H, deleted(X,L1,L2).
deleted(X, [X|L1], L2) :- deleted(X,L1,L2).
deleted(_, [], []).
:- begin_tests(deleted_nondeterministic).
test(empty, all(RR = [[]])) :- deleted(1,[],RR).
test(not_exists, all(RR = [[2,3,4,5,6]])) :- deleted(1,[2,3,4,5,6],RR).
test(exists_once, all(RR = [[2,4,5,6]])) :- deleted(1,[2,1,4,5,6],RR).
test(exists_once_end, all(RR = [[2,3,4,5]])) :- deleted(1,[2,3,4,5,1],RR).
test(exists_multi, all(RR = [[2,4,6]])) :- deleted(1,[2,1,4,1,6],RR).
test(exists_only, all(RR = [[]])) :- deleted(1,[1,1,1,1,1],RR).
:- end_tests(deleted_nondeterministic).
rt :- run_tests(deleted_nondeterministic).
as I mentioned in the coments, that question has already been answered in the site.
I wrote a similar approach that you may find useful
delete(_, [], []):- !.
delete(X, [X|L1], L2):- !, delete(X,L1,L2).
delete(X, [H|L1], [H|L2]):- !,delete(X,L1,L2).
Feel free to askme any question about the implementation, cheers!

Print elements of a list but handle last element differently

I have written a predicate that prints out each element in the list except the last. The last element should be handled differently; it should print LAST! instead. This is what I have.
write_data([]).
write_data([X]) :-
!, write('LAST!'), nl.
write_data([X | Rest]) :-
write(x), nl,
write_data(Rest).
Is there a better way? Is there a way to do this without the cut?
You can avoid the cut, by performing unification with a list that has at least two elements, like:
write_data([]).
write_data([_]) :-
write('LAST!'),
nl.
write_data([X|Rest]) :-
Rest = [_|_],
write(X), nl,
write_data(Rest).
We can furthermore avoid the double unpacking with a helper predicate:
write_data([]).
write_data([H|T]) :-
write_data(T, H).
write_data([], _) :-
write('LAST!'), nl.
write_data([H|T], X) :-
write(X), nl,
write_data(T, H).
A common definition for a last/2 predicate that provides access to the last element of a list is:
last([Head| Tail], Last) :-
last(Tail, Head, Last).
last([], Last, Last).
last([Head| Tail], _, Last) :-
last(Tail, Head, Last).
When called with the first argument bound to a closed list, the auxiliary predicate, last/3, avoids spurious choice-points assuming a Prolog system implementing, as common, first-argument indexing. Can you modify this predicate to do what you want?
The general rule of thumb for cut removal is to note what was true in the clause that contains the cut , then make sure that is false in the other clause(s) .
Thus :
write_data([]).
write_data([X]) :-
/*!,*/write('LAST!'), nl.
write_data([X | Rest]) :-
dif(Rest,[]) , /**/
write(x), nl,
write_data(Rest).

STRIPS algorithm in prolog dosen't stop

I'm learning Prolog and I'm writing STRIPS algorithm. Exactly I try to write it because it doesn’t work and unfortunately, I can't understand why.
Simply, the program doesn't stop, it thinks what kind is next action but doesn't apply it. Below, I post a code of my program, I hope that there will be somebody with more experience could put me in right direction.
May be the recursion is wrong but I can't find a mistakes.
Thank you!
The plan/2 and action/4 are predicate written in world representation file.
strips(Plan):-
[worldblock_rap],
plan(Initstate,Goallist),
strip1(Initstate,Goallist,RevPlan,[]),
reverse(RevPlan, Plan).
%strips(+GoalList, +State, +Plan, +ForbiddenActions
strip1(State,Goallist,_,_):-
there_is(State, Goallist).
%strips(+GoalList, +State, +Plan, +ForbiddenActions
strip1(State,Goallist,Plan,ForibiddenActions):-
%*****choose the right action******
action(Ac,Prec,Del,Add),
there_is(Goal, Goallist),
\+there_is(Goal, State),
there_is(Add,Goal),
\+belongs(Ac,ForibiddenActions),
%*****************
%******achive its precondition*******
strip1(TmpState1,Prec,TmpPlan1,[Ac| ForibiddenActions]),
%********************************
%***********Update the new plan with precondition's subplan and this action
apply_rule(Ac,Del,Add,TmpState1,NewState),
append([Ac|TmpPlan1], Plan, NewPlan),
strip1(NewState,Goallist,NewPlan,[Ac|ForibiddenActions]).
apply_rule(Ac,Dellist,Addlist,State,NewState):-
nl,write("doing"), write(Ac), ttyflush,
delete_list(State, Dellist,TmpState),
append(Addlist,TmpState,NewState).
reverse([],A,A).
reverse([X|L],L1,A):-reverse(L,[X|L1],A).
delete_list([H|T], List, Final):-
remove(H, List, Tmp),
delete_list(T, Tmp, Final).
delete_list([], List, List).
remove(X, [X|T], T).
remove(X, [H|T], [H|R]):-
remove(X, T, R).
append([H|T], L1, [H|L2]):-
append(T, L1, L2).
append([], L, L).
belongs(X, [X|_]).
belongs(X, [_|T]):-
belongs(X, T).
there_is([], _).
there_is([X|T], L):-
belongs(X, L),
there_is(T, L).
This the predicate of world block representation:
plan([on(a,d),on(b,table),on(c,b),on(d,table),top(a),top(c)],
[on(a,table),on(b,a),on(c,b),on(d,c),top(d)]).
action(putdown(X),
[top(X)],
[top(X),on(X,Y)],
[on(X,table),top(Y)]).
action(pickup(X,Y),
[on(X,table),top(Y)],
[on(X,table),top(Y)],
[on(X,Y),top(X)]).
Below there is onother representation of monkey world. Also with this file the planner doesn't work.
plan([at(monkey,a),at(box,c),on(monkey,floor),on(box,floor),status(banana,notpick),at(banana,d)],
[on(monkey,box),on(box,floor),status(banana,pick),at(banana,d),at(monkey,d),at(box,d)]).
action(
go(X,Y),
[at(monkey,X),on(monkey,floor)],
[at(monkey,X)],
[at(monkey,Y)]).
action(
push(B,X,Y),
[at(monkey,X),at(B,X),on(B,floor),on(monkey,floor)],
[at(monkey,X),at(B,X)],
[at(monkey,Y),at(B,Y)]).
action(
climb_on(B),
[at(monkey,X),at(box,X),on(monkey,floor),on(box,floor)],
[on(monkey,floor)],
[on(monkey,B)]).
action(
grab(B),
[status(B,notpick),on(monkey,box),at(B,X),at(monkey,X),at(box,X)],
[status(B,notpick)],
[status(B,pick)]).

Help with simple prolog exercise

I haven't been able to solve this prolog exercise. I was hoping someone here could give me some hints or post a solution. Thanks in advance.
Database:
lig(super, porto).
lig(super, benfica).
lig(super, sporting).
lig(honra, feirense).
lig(honra, guimaraes).
jog(sporting, ricardo, gr).
jog(guimaraes, cleber, de).
jog(feirense, edgar, me).
jog(porto, quaresma, av).
jog(porto, helton, gr).
jog(benfica, simao, av).
jog(sporting, moutinho, me).
The sample output:
?- calcula(Lista).
Lista = [super-[porto-[quaresma,helton], benfica-[simao], sporting-
[moutinho,ricardo]], honra-[ feirense-[edgar], guimarães-[cleber]]].
My procedure:
calcula(Lista) :-
findall(Lig-[Eq-[X]],
(lig(Lig, Eq), findall(Jog, jog(Eq, Jog, _), X)),
Lista).
My output (which is wrong!).
Lista = [super-[porto-[[quaresma, helton]]], super-[benfica-[[simao]]], super-[sporting-[[ricardo, moutinho]]], honra-[feirense-[[edgar]]]
I see in the zfm's solution, the predicate lig(Lig, _) becomes true 5 times so there is some duplication in the final list. You can use the predicate setof/3 and existential quantified variable Eq0^ to remove duplication:
calcula(T) :- setof(Lig-X, Eq0^(lig(Lig, Eq0),
findall(Eq-U, (lig(Lig,Eq), findall(Jog, jog(Eq, Jog, _), U)), X)), T).
Since I'm so interested to the question, I try it a lot.
Well, this is, I believe, not the best answer. However I get the result.
calcula(Ans):-findall(Lig-X, (lig(Lig, _),
findall(Eq-U, (lig(Lig,Eq), findall(Jog, jog(Eq, Jog, _), U)), X)), T),
removeEq(T,Ans).
removeEq([A-B,A-_|Tail], [A-B|TailChanged]) :- !, removeEq([A-B|Tail],
[A-B|TailChanged]).
removeEq([A-B,C-D|Tail], [A-B,C-D|TailChanged]) :- removeEq([A-B|Tail],
[A-B|TailTemp]), removeEq([C-D|TailTemp], [C-D|TailChanged]).
removeEq([X], [X]).
The removeEq is needed because there are duplicated answer (I don't know how not to duplicate it)
This is not shorter than zfm's answer, but it is "simpler" in the way that it only uses basic prolog constructs to construct the list directly. (No removal of duplicates afterward.) There is some code duplication which probably could be gotten rid of to get a shorter answer.
g(Second, [Third|Rest], Done) :- jog(Second, Third,_),
not(member(Third, Done)),!,
g(Second, Rest, [Third|Done]).
g(_,[],_).
f(First, [Second-New|Rest], Done) :- lig(First, Second),
not(member(Second, Done)),!,
g(Second, New, []),
f(First, Rest, [Second|Done]).
f(_,[],_).
h([First-X|Lista], Done):-
lig(First,_),
not(member(First, Done)),!,
f(First, X, []),
h(Lista,[First|Done]).
h([], _).
calcula(X) :- h(X, []).

Resources