% Discourse 2009


go :-
	retractall(tel(_)), assert(tel(1)),	
	%blank slate
	DRS = drs([], []),
	S = [ [ik,zie,een,rode,kat], [ik,zie,een,blauwe,mat], [de,kat,zit,op,de,mat] ],
	analyse(S, DRS).  

gomuis :-
	retractall(tel(_)), assert(tel(1)),	
	%blank slate
	DRS = drs([], []),
	S = [
		[in,het,midden,van,het,hartje,van,het,binnenste,van,het,muiskleurig,gebergte,woonde,de,weerwolf], 
		['hij', 'was', 'groot', 'en', 'verschrikkelijk'], 
		['zijn', 'ogen', 'sproeiden', 'vuur', 'en', 'zijn', 'tong', 'had', 'karteltjes'],
		['hij', 'had', 'lange', 'witte', 'scherpe', 'tanden'], 
		['iedere', 'avond', 'stiet', 'hij', 'een', 'gebrul', 'uit'], 
		%waarvan 
		['het', 'hele', 'muiskleurige', 'gebergte', 'sidderde'],
		['dat', 'is', 'de', 'weerwolf']],
	analyse(S, DRS).  

go(S) :-
	retractall(tel(_)), assert(tel(1)),	
	%blank slate
	DRS = drs([], []),
	analyse([S], DRS).

goprince :-
	retractall(tel(_)), assert(tel(1)),	
	DRS = drs([], []),
	S = [[once, when, i, was, six, years, old],
		[i, saw, a, magnificent, picture, in, a, book], 
		[called, true, stories, from, nature], 
		[about, the, primeval, forest]],
	%It was a picture of a boa constrictor in the act of swallowing an animal. Here is a copy of the drawing. 
	analyse(S, DRS).

% Groep 1: Lexicon
%lex(word, VariablesToEat, Features).
%Features:
%	- eat, find, bind
%	- part of speech (det, pron, neg, prep, adj, noun, verb)
%	- after, before, next (difference between before and next is that next 
%				only matches the word directly next to it)
%	- male, female, neuter
%	- plural, singular
%	- animate
%
% All features take one argument. The argument is anonymous (_) if it is about
% the word itself, or it specifies a constraint for eat/find/bind.

%
pos(tempadv, [X], [adv(T), eat(X), verb(X), bind(T)], T).	%introduce new reference time
pos(adv, [X], [adv(T), eat(X), adv(X)], T).
pos(adv, [X], [adv(T), eat(X), adj(X)], T).
pos(adj, [X], [adj(T), eat(X), next(X)], T).
pos(adj, [X], [adj(T), eat(X), adj(X)], T).
pos(noun, [], [noun(T)], T).
pos(noun, [X], [noun(T), eat(X), next(X), noun(X)], T). %eg. picture book = picture -> book
pos(aninoun, [], [noun(T), animate(T)], T).
pos(prep, [X,Y], [prep(T), eat(X), eat(Y), before(X), next(Y)], T).	%preposition modifies its two closest neighbors
pos(verb1, [X], [eat(X), before(X), verb(T), noun(X)], T).
pos(verb2, [X,Y], [eat(X), eat(Y), before(X), verb(T), noun(X), noun(Y)], T).
pos(aniverb2, [X,Y], [eat(X), eat(Y), before(X), verb(T), animate(X), noun(Y)], T).

%
lexclass(tempadv, [once, when]).
lexclass(adj, [six, old, magnificent, true, primeval]).
lexclass(noun, [years, picture, book, stories, nature, forest, act, swallowing, copy, drawing]).
lexclass(aninoun, [boa,constrictor,animal]).
lexclass(verb1, []).
lexclass(verb2, [is, was, called]).
lexclass(aniverb2, [is, was, saw]).
lexclass(prep, [in, of, on, at, under, above, from, about]).

%
lex(i, [], [pron(T), find(_), animate(T), male(T)], T).
lex(i, [], [pron(T), find(_), animate(T), female(T)], T).
lex(a, [X], [det(T), bind(T), eat(X), next(X)], T).
lex(the, [X], [det(T), find(_), eat(X), next(X)], T).

lex(A, B, C, D) :- word(A,B,C,D).
lex(Word, Vars, Feat, Id) :-
	lexclass(POS, Words), member(Word, Words),
	pos(POS, Vars, Feat, Id).


lex(ik, [], [pron(T), find(Y), animate(Y), male(Y)], T).
lex(ik, [], [pron(T), find(Y), animate(Y), female(Y)], T).
lex(zie, [X, Y], [eat(X), eat(Y), before(X), verb(T), animate(X), noun(Y)], T).
lex(een, [X], [det(T), eat(X), bind(_Y), next(X), takefeat(X)], T). %, takefeat(X)]).
lex(rode, [X], [eat(X), adj(T), noun(X), next(X)], T).
lex(kat, [], [noun(Y), animate(Y), male(Y)], Y).
lex(blauwe, [X], [adj(T), eat(X), noun(X), next(X)], T).
lex(zit, [X], [eat(X), before(X), verb(T)], T).
lex(niet, [X], [eat(X), before(X), verb(X), neg(T)], T).
lex(mat, [], [noun(T), male(T)], T).
lex(op, [X,Y], [prep(T), eat(X), eat(Y), before(X), next(Y), verb(X)], T).

lex(in, [X, Y], [prep(T), eat(X), eat(Y), verb(X), prep(Y), after(Y)], T).
lex(het, [X], [det(T), find(_Y), eat(X), next(X), takefeat(X)], T). %, takefeat(X)]).
lex(midden, [], [noun(T), neuter(T)], T).
lex(van, [X,Y], [prep(T), eat(X), eat(Y), noun(X), before(X), prep(Y), after(Y)], T).
lex(van, [X,Y], [prep(T), eat(X), eat(Y), next(Y), noun(X), before(X)], T).
lex(hartje, [], [noun(T), neuter(T)], T).
lex(binnenste, [], [noun(T), neuter(T)], T).
lex(muiskleurig, [X], [adj(T), eat(X), next(X), noun(X)], T).
lex(gebergte, [], [noun(X), neuter(X)], X).
lex(woonde, [X], [verb(T), singular(T), past(T), eat(X), noun(X), animate(X)], T).
lex(de, [X], [det(T), find(_), eat(X), next(X), male(X), takefeat(X)], T).
lex(de, [X], [det(T), find(_), eat(X), next(X), female(X)], T). %, takefeat(X)]).
lex(de, [X], [det(T), find(_), eat(X), next(X), plural(X)], T). %, takefeat(X)]).
lex(weerwolf, [], [noun(X), animate(X), male(X)], X).

% hij was groot en verschrikkelijk
word(hij,[],[find(X),pronoun(This), male(X),animate(X)],This).
word(was,[X,Y],[verb(This),pastTense(This),singular(This), eat(X),eat(Y)],This).
word(groot,[],[ adj(This)],This).
word(en,[X,Y],[npconj(This),eat(X),eat(Y),before(X),after(Y)],This). % een 'en' zoals in een opsomming
word(verschrikkelijk,[],[ adj(This)],This).

% zijn ogen sproeiden vuur en zijn tong had karteltjes
word(zijn,[X],[pronoun(This),eat(X),noun(X),find(Y),male(Y)],This).
word(ogen,[],[ noun(This),plural(This),inanimate(This)],This).
word(sproeiden,[X,Y],[verb(This),plural(This),pastTense(This),eat(X),eat(Y), noun(Y)], This).
word(vuur,[],[noun(This),inanimate(This),singular(This),neuter(This)],This).
word(en,[X,Y],[conn(This),eat(X),eat(Y), before(X), after(Y), verb(X),verb(Y)], This). % een 'en' die twee complete zinnen verbindt
word(tong,[],[noun(This),inanimate(This),singular(This),female(This)],This).
word(had,[X,Y],[verb(This), singular(This),pastTense(This),eat(X),eat(Y), noun(Y)],This).
word(karteltjes,[],[noun(This),plural(This)],This).
 
% hij had lange witte scherpe tanden en
word(lange,[X],[adj(This),eat(X),next(X),takefeat(X)],This).
word(witte,[X],[adj(This),eat(X),next(X),takefeat(X)],This).
word(scherpe,[X],[adj(This),eat(X),next(X),takefeat(X)],This).
word(tanden,[],[ noun(This),plural(This),inanimate(This)],This).

% iedere avond om zes uur stiet hij een gebrul uit waarvan het hele muiskleurige gebergte sidderde
word(iedere,[X,Y],[univ(This), noun(X), next(X), eat(X), takefeat(X), verb(Y), eat(Y)], This).
word(avond,[],[noun(This),inanimate(This),singular(This),male(This)],This).
word(om,[X,Y],[eat(X),after(X),noun(X), verb(Y),eat(Y)], _This).
word(zes,[X],[num(This),eat(X),noun(X),after(X),takefeat(X)],This).
word(uur,[],[noun(This),neuter(This),inanimate(This)],This).
word(stiet,[X,Y,Z],[verb(This),pastTense(This),singular(This),eat(X),eat(Y),eat(Z),animate(X),noun(Y),particle(Z)],This).
word(een,[X],[det(This), bind(This),eat(X),noun(X),singular(X)],This).
word(gebrul,[],[noun(This),singular(This),neuter(This),inanimate(This)],This).
% deze 'uit' hoort bij 'stiet' (uitstoten)
% ik maak er daarom een particle van en geen preposition
% zie http://en.wikipedia.org/wiki/Preposition_and_postposition#Particles
% -- Jeroen

word(uit,[],[particle(This)],This).
word(waarvan,[X,Y],[pronoun(X),verb(X),eat(X),eat(Y)],_This). % 'waarvan' is een betrekkelijk voornaamwoord
word(hele,[X],[ adj(This),eat(X),noun(X),takefeat(X)],This).
word(muiskleurige,[X],[adj(This) ,noun(X),takefeat(X), eat(X)],This).
word(sidderde,[X],[ verb(This),pastTense(This),singular(This),noun(X),eat(X)],This).

 

% dat is de weerwolf

word(dat,[X],[pronoun(This),noun(X),find(X)],This).
word(is, [X,Y],[verb(This),presentTense(This),singular(This),noun(X),eat(X),eat(Y)],This).

:- dynamic tel/1.

analyse([], _DRS).
analyse([Sentence | Rest], DRS) :-
	interpret(Sentence, Meaning, DRS),
	writeln('Interpretation: '), writelist(Meaning), nl,
	%generatie check?
	docontext(Meaning, Meaning, DRS, drs(Ref, Cond)),
	writeln('Sentence: '), writeln(Sentence), nl,
	writeln('Meaning: '), writelist(Meaning), nl,
	writeln('Context: '),
	% 'pretty-print' DRS
	writeln(Ref), writeln('--------------'), writelist(Cond), nl,
	analyse(Rest, drs(Ref, Cond)).

writelist([]).
writelist([Head | Tail]) :-
	writeln(Head),
	writelist(Tail).

% Groep 2
interpret(S, M, DRS):-
	def(S, M),
	eat(M, R1, M, M, det),
	eat(M, R2, R1, M, adj),
	eat(M, R3, R2, M, verb),
	eat(M, R4, R3, M, prep),
	eat(M, R5, R4, M, _),
	write('Not eaten: '), writeln(R5),
	find(M, M, DRS).

% Get word definitions and assign unique word IDs
def([], []).
def([H|T], [lex(H, A2, A3, Tel)|M]) :-
	lex(H, A2, A3, Tel),
	tel(Tel),
	NewTel is Tel + 1,
	retractall(tel(_)),
	assert(tel(NewTel)),
	def(T, M).

eat([], F, F, _, _).
eat([lex(_,_,Feat, Id) | Tail], RFood, F, Meaning, Type) :-
	eat(Tail, Food, F, Meaning, Type),
	((var(Type) ; (P =.. [Type, Id], memb(P, Feat))) -> 
		doeat(Feat, Id, Food, RFood, Meaning)
	;
		RFood = Food).


memb(A, [H|T]) :- 
	A == H 
	;
	memb(A,T).

doeat(Feat, Id, Food, RRFood, Meaning) :-
	((select(eat(X), Feat, Rest), var(X)) ->
		doeat(Rest, Id, Food, RFood, Meaning),
		%find all constraints specified for the referent we need to find:
		findall(C, getconstraint(C, X, Rest), Constraints),
		%instantiate X with word satisfying constraints
		(select(takefeat(_), Constraints, RConstraints) ->
			getFood(X, Id, RConstraints, RFood, TFood),
			% get features from word that was eaten
			member(lex(_,_,XFeat, X), Food),
			append(Feat, XFeat, RFeat),
			% put those features in the current word
			select(lex(W,V,Feat,Id), TFood, Tmp),
			RRFood = [lex(W,V,RFeat,Id) | Tmp]
		;
			getFood(X, Id, Constraints, RFood, RRFood))
	;
		RRFood = Food).

getconstraint(C, X, Feat) :-
	member(C, Feat),
	C =.. [_Pred, Y],
	X == Y.

getFood(X, Id, Constraints, Meaning, Rest) :-
	% if there is a before constraint, reverse to match closest word first:
	(member(before(_), Constraints) ->
		reverse(Meaning, RM),
		select(lex(_, _, Feats, FoodId), RM, RF),
		reverse(RF, Rest)
	;
		select(lex(_, _, Feats, FoodId), Meaning, Rest)),
	forall(member(C, Constraints), checkconstraint(C, Feats, Id, FoodId)),
	\+ Id = FoodId, %don't eat yourself.
	% don't eat something which has already been eaten: (causes problems with current lexicon)
	%\+ (member(lex(_,_,F,_), Meaning), member(eat(I), F), I == FoodId),
	X = FoodId.

checkconstraint(C, Feats, Id, FoodId) :-
	(C = before(_), FoodId < Id)
	;
	(C = after(_), FoodId > Id)
	;
	% words directly next to each other
	(C = next(_), FoodId =:= Id + 1)
	;
	( \+ C = after(_), \+ C = before(_), \+ C = next(_),
	member(C, Feats)).

%get properties from word that was eaten, and look in DRS for matching
%conditions
find([], _, _).
find([lex(W1,_,Feat, Id) | Tail], Meaning, DRS) :-
	find(Tail, Meaning, DRS),
	(select(find(X), Feat, Rest) ->
		(select(eat(Y), Feat, _) ->
			% eg. the -> cat, get constraints from cat.
			member(lex(W,_,Feat2, Y), Meaning),
			%find all constraints specified for the referent we need to find:
			findall(C, getconstraint(C, Y, Feat2), Constraints)
		;
			% eg. he, get constraints from own features.
			W = W1,
			findall(C, getconstraint(C, X, Rest), Constraints)),
		%instantiate X with referent satisfying constraints,
		%or if that fails, it will get bound later.
		try((findRef(X, W, Id, Constraints, DRS),
		% no two findings in sentence should be identical:
		%\+ (member(A, Rest), 
		%	A = lex(_,_,F1,_),
		%	member(find(C), F1),
		%	nonvar(C), C = X),
		true))
	;	
		true).

% try calling Pred, but succeed anyway if it fails
try(Pred) :-
	call(Pred).
try(_Pred).


% find a suitable referent
findRef(X, W, Id, Constraints, drs(Ref, Cond)) :-
	member(X, Ref),		%instantiation happens here!
	P =.. [W, Y],
	%the word/predicate is already in the DRS
	(member(P, Cond) ->
		X = Y,
		% do not find myself:
		\+ X = Id
	;
		% we have a word and some constraints, look in conditions if it
		% contains a word/predicate which satisfies those conditions
		checkref(Constraints, Cond, X),
		\+ X = Id).
	% maybe look into past meanings as well? (previous sentences)
	% (should be something more sophisticated:
	%	een kat .... de kat <-- look for kat(X) in DRS
	%	de man .... hij <-- look for male referent in DRS)
	%	when a referent has already been found in a sentence,
	%	assume we need to find a *different* referent:
	%	een kat en een mat <- Ex,y cat(x) ^ mat(y) ^ not(x = y)

findRef(X, W, Id, Constraints, drs(_Ref, Cond)) :-
	member(imp(DRS1, DRS2), Cond),
	(findRef(X, W, Id, Constraints, DRS1)
	;
	findRef(X, W, Id, Constraints, DRS2)).

findRef(X, W, Id, Constraints, drs(_Ref, Cond)) :-
	member(not(DRS), Cond),
	findRef(X, W, Id, Constraints, DRS).


% take a DRS condition and see if it satisfies the constraints according to lexicon:
checkref([], _Cond, _Ref).
checkref([C | Tail], Cond, Ref) :-
	checkref(Tail, Cond, Ref),
	member(P, Cond),
	P =.. [W, Ref],
	lex(W,_,Feat,_),
	member(C, Feat).
	
% Groep 3: context model
gocontext :-
	retractall(tel(_)),
	assert(tel(1)),
	DRS = drs([], []),
	Meaning = [lex(hij, [], [find(1), pronoun(1), male(1), singular(1), animate(1)], 1),
		lex(had, [1, 3], [verb(2), pastTense(2), eat(1), eat(3), singular(1), noun(1), before(1), noun(3), after(3)], 2),
		lex(lange, [4], [adj(3), eat(4), noun(4), next(4), same_features(3, 4)], 3),
		lex(witte, [5], [adj(4), eat(5), noun(5), next(5), same_features(4, 5)], 4),
		lex(scherpe, [6], [adj(5), eat(6), noun(6), next(6), same_features(5, 6)], 5),
		lex(tanden, [], [noun(6), plural(6), inanimate(6)], 6),
		lex(en, [2, 18], [conn(7), eat(2), eat(18)], 7),
		lex(iedere, [9, 13], [univ(8), eat(9), noun(9), next(9), singular(9), same_features(8, 9), verb(13), eat(13)], 8),
		lex(avond, [], [noun(9), inanimate(9), singular(9), male(9)], 9),
		lex(om, [8, 11], [prep(10), eat(8), before(8), noun(8), eat(11), noun(11), after(11)], 10),
		lex(zes, [12], [det(11), eat(12), noun(12), next(12), same_features(11, 12)], 11),
		lex(uur, [], [noun(12), neuter(12), inanimate(12)], 12),
		lex(stiet, [14, 15, 17], [verb(13), pastTense(13), eat(14), eat(15), eat(17), singular(14), animate(14), noun(15), after(15), particle(17)], 13),
		lex(hij, [], [find(14), noun(14), male(14), singular(14), animate(14)], 14),
		lex(een, [16], [det(15), bind(15), eat(16), next(16), noun(16), singular(16), same_features(15, 16)], 15),
		lex(gebrul, [], [noun(16), singular(16), neuter(16), inanimate(16)], 16),
		lex(uit, [], [particle(17)], 17) ,
		lex(waarvan, [10, 23], [prep(18), eat(10), eat(23), prep(10), verb(23)], 18),
		lex(het, [20], [det(19), find(19), eat(20), next(20), neuter(20), same_features(19, 20)], 19),
		lex(hele, [21], [adj(20), eat(21), noun(21), next(21), same_features(20, 21)], 20),
		lex(muiskleurige, [22], [adj(21), noun(22), next(22), same_features(21, 22), eat(22)], 21) ,
		lex(gebergte, [], [noun(22), neuter(22), singular(22)], 22),
		lex(sidderde, [19], [verb(23), pastTense(23), singular(19), before(19), noun(19), eat(19)], 23)],
	/*
	Meaning = [   lex(in, [14, 4], [prep(1), eat(14), eat(4), verb(14), prep(4), 
		   after(4)], 1),
		   lex(het, [3], [det(2), find(2), eat(3), next(3), neuter(3), same_features(2, 3)], 2),
		   lex(midden, [], [noun(3), neuter(3)], 3),   
		   lex(van, [2, 7], [prep(4), eat(2), eat(7), noun(2), prep(7), before(2), after(7)], 4)    ,
		   lex(het, [6], [det(5), find(5), eat(6), next(6), neuter(6),    
		   same_features(5, 6)], 5)    ,
		   lex(hartje, [], [noun(6), neuter(6)], 6)  ,
		   lex(van, [5, 10], [prep(7), eat(5), eat(10), noun(5), prep(10),
		   before(5), after(10)], 7)   ,
		   lex(het, [9], [det(8), find(8), eat(9), next(9), neuter(9),    
		   same_features(8, 9)], 8)    ,
		   lex(binnenste, [], [noun(9), neuter(9)], 9)      ,
		   lex(van, [8, 11], [prep(10), eat(8), eat(11), noun(8), noun(11),      
		   before(8), after(11)], 10)  ,
		   lex(het, [12], [det(11), find(11), eat(12), next(12), neuter(12),     
		   same_features(11, 12)], 11) ,
		   lex(muiskleurig, [13], [adj(12), eat(13), noun(13), next(13),  
		   same_features(12, 13)], 12) ,
		   lex(gebergte, [], [noun(13), neuter(13), singular(13)], 13)    ,
		   lex(woonde, [15], [verb(14), singular(14), past(14), eat(15),  
		   noun(15), animate(15)], 14) ,
		   lex(de, [16], [det(15), find(15), eat(16), noun(16), next(16), 
		   male(16), same_features(15, 16)], 15)     ,
		   lex(weerwolf, [], [noun(16), animate(16), male(16)], 16)],
	*/
	docontext(Meaning, Meaning, DRS, NewDRS),
	writeln(NewDRS).

gocontext1 :-
	M=[lex(hij, [], [find(1), noun(1), male(1), singular(1), animate(1)], 1), lex(was, [1, 4], [verb(2), pastTense(2), eat(1), eat(4), singular(1), noun(1), before(1), prep(4), after(4)], 2), lex(groot, [], [noun(3)], 3), lex(en, [3, 5], [npconj(4), eat(3), eat(5), noun(3), before(3), noun(5), after(5)], 4), lex(verschrikkelijk, [], [noun(5)], 5)],
	docontext(M,M,drs([2, 5, 8, 11, 15], [in(15, 2), midden(2), van(2, 5), hartje(5), van(5,8), binnenste(8), van(8, 11), gebergte(11), muiskleurig(11), woonde(15),weerwolf(15)]),ND),
	writeln(ND).

%bind new referents
dobind([], _, DRS, DRS).
dobind([lex(Word, Vars, Feats, Id) | Rest], M, drs(Ref, Cond), drs(NewRef, Cond)) :-
	dobind(Rest, M, drs(Ref, Cond), drs(R, Cond)),
	((member(bind(V), Feats) ; (member(find(V), Feats), var(V))) ->
		V = Id,
		%Add variable to M:
		member(lex(Word, Vars, Feats, Id), M),
		%Add new variable to Ref:
		union(R, [V], NewRef)
	;
		% ?! nonvar(Ref),
		NewRef = R).

% wrapper
docontext(Meaning, Meaning, DRS, NewDRS) :-
	dobind(Meaning, Meaning, DRS, Tmp),
	Tmp = drs(Ref, Cond),
	%handle negation
	((select(lex(_, _, C, _), Meaning, Rest), member(neg(_), C)) ->
		docontext(Rest, Rest, drs([], []), drs(NewRef, TempCond)),
		subtract(TempCond, Cond, NewCond),
		NewDRS = drs(Ref, [not(drs(NewRef, NewCond)) | Cond])
	;
		% handle sentence conjunction
		((select(lex(_, _, D, _), Meaning, _Rest), member(conn(_), D)) ->
			append(A, [lex(_,_,D,_)|B], Meaning),
			docontext(A, A, DRS, drs(NewRef1, TempCond1)),
			docontext(B, B, DRS, drs(NewRef2, TempCond2)),
			% merge DRSes
			union(NewRef1, NewRef2, NewRef3),
			union(NewRef3, Ref, NewRef),
			union(TempCond1, TempCond2, TempCond3),
			union(TempCond3, Cond, NewCond),
			NewDRS = drs(NewRef, NewCond)
		;
			% handle universal quantification
			((select(lex(_, _, E, _), Meaning, Rest), member(univ(_), E)) ->
				select(eat(A), E, ER), %variable
				select(eat(B), ER, _), %sentence
				select(lex(W,_V,_F,A), Rest, RRest),
				%one-word hack for variable:
				Pred =.. [W, A],
				DRS1 = drs([A], [Pred]),
				%AM = [lex(W,V,F,A)], %plus more words?
				%eg. iedere donkere avond
				%docontext(AM, AM, drs([],[]), DRS1),
				docontext(RRest, RRest, drs([],[]), DRS2),
				DRS2 = drs(Ref2, Cond2),
				subtract(Ref2, Ref, NRef2),
				union(Cond, [forall(DRS1, drs(NRef2, Cond2))], NewCond),
				NewDRS = drs(Ref, NewCond)
			;
				%normal sentence, stop recursing
				context(Meaning, Meaning, Tmp, NewDRS)))).

context([], _, NewDRS, NewDRS).
context([lex(Word, Vars, Feats, Id) | Rest], M, drs(Ref, Cond), Result) :-
	% add conditions to DRS
	% normal words, ie., neither a determiner or pronoun, has arguments:
	(\+ (member(det(_), Feats) ; member(npconj(_), Feats) ; member(pronoun(_), Feats) ; Vars = []) ->
		% handle NP conjunctions and copula
		(member(eat(X), Feats), member(lex(_,_,XFeats,X), M), member(npconj(X), XFeats) ->
			select(eat(A), XFeats, XRest),
			select(eat(B), XRest, _),
			(Vars = [Y, X] ->
				XVars1 = [Y, A],
				XVars2 = [Y, B]
			;
				XVars1 = [A, Y],
				XVars2 = [B, Y]),
			((deref(XVars1, M, DerefVars1),
			  deref(XVars2, M, DerefVars2)) ->
				Pred1 =.. [Word | DerefVars1],
				Pred2 =.. [Word | DerefVars2],
				union(Ref, DerefVars1, Tmp),
				union(Tmp, DerefVars2, NewRef)
			;
				%copula, verb has no meaning
				member(lex(Word1, _,_, A), M),
				member(lex(Word2, _,_, B), M),
				Pred1 =.. [Word1, Y],
				Pred2 =.. [Word2, Y],
				union(Ref, [Y], NewRef)),
			union(Cond, [Pred1, Pred2], NewCond)
		;
			%resolve word IDs to discourse referents
			(deref(Vars, M, DerefVars) ->
				Pred =.. [Word | DerefVars],
				union(Ref, DerefVars, NewRef)
			;
				%copula, verb has no meaning
				% eg. hij was groot:
				% get ref from 'hij', condition from 'groot'
				select(eat(A), Feats, XRest),
				select(eat(B), XRest, _),
				member(lex(_W,_,AF,A), M),
				member(lex(Word,_,_,B), M),
				member(bind(A), AF),
				Pred =.. [Word, A],
				union(Ref, [A], NewRef)),
			union(Cond, [Pred], NewCond)),
		context(Rest, M, drs(NewRef, NewCond), Result)
	;	%handle determiners
		((member(det(_), Feats) ; member(pronoun(_), Feats)) ->
			(member(find(F), Feats)
			;
			member(bind(F), Feats)), 
			%recurse until word which hasn't eaten (noun)
			findconditions(F, Feats, M, Preds),
			union(Cond, Preds, NewCond),
			context(Rest, M, drs(Ref, NewCond), Result)
		;
			% a word which hasn't eaten anything but is
			% eaten directly by a verb should bind a new referent
			% and be added as condition.
			((member(lex(_,_,VFeat,_), M), 
			member(eat(Id), VFeat), 
			(member(verb(_), VFeat) ; member(prep(_), VFeat))) ->
				Pred =.. [Word, Id],
				union(Cond, [Pred], NewCond),
				union(Ref, [Id], NewRef),
				context(Rest, M, drs(NewRef, NewCond), Result)
			;
				% other words without arguments are ignored:
				context(Rest, M, drs(Ref, Cond), Result)))).

% eg. de -> rode -> kat should yield [kat, rode]
findconditions(_F, Feats, _Meaning, []) :-
	\+ member(eat(_X), Feats).
findconditions(F, Feats, Meaning, [Pred | Tail]) :-
	member(eat(X), Feats),
	select(lex(AteWord, _, NFeats, X), Meaning, Rest),
	Pred =.. [AteWord, F],
	findconditions(F, NFeats, Rest, Tail).

% dereference word IDs to their original discourse referents
% (ie., word ID from when referent was introduced)
deref([], _Meaning, []).
deref([V | Vars], Meaning, [R | RVars]) :-
	deref(Vars, Meaning, RVars),
	%find word referred to:
	select(lex(_, _, Feats, V), Meaning, Rest),
	%either the discourse referent has been found:
	(member(find(R), Feats)
	;
	%or it has or will be bound:
	member(bind(R), Feats)
	;
	% implicit bind: bare nouns
	(member(lex(_,_, Feats2, _), Meaning), 
	member(eat(V), Feats2),
	member(verb(_), Feats2),
	R = V)
	;
	%recurse (determiner contains find/bind).
	(\+ member(bind(_), Feats),
	\+ member(find(_), Feats),
	((member(verb(_), Feats) 
	; member(prep(_), Feats)
	; member(npconj(_), Feats)
	; member(adv(_), Feats)) ->
		% resolve verb to one of its arguments 
		%(which argument is part of ambiguity of language...)
		member(eat(Foo), Feats)
	;
		%backwards: eg. kat -> rode -> de 
		member(lex(_,_, Feats2, Foo), Meaning), 
		member(eat(V), Feats2)),
	% prevent cycles by passing Rest, ie., without the word we just tried:
	deref([Foo], Rest, [R]))).
