Modelleren en Programmeren: Prolog Marijn Schraagen 15 januari 2016 Herhaling Definite Clause Grammars DCG s met argumenten DCG s met returnwaardes
Herhaling
Lijsten Een lijst is een sequentie van termen Getallen, strings, variabelen, predicaten, rekenexpressies, andere lijsten Willekeurige lengte Notatie: vierkante haken [] en komma Voorbeeld: [a,b,[1,2,[3,3],x], Jan ]
Lijsten Een lijst is een sequentie van termen Getallen, strings, variabelen, predicaten, rekenexpressies, andere lijsten Willekeurige lengte Notatie: vierkante haken [] en komma Voorbeeld: [a,b,[1,2,[3,3],x], Jan ] Lijstoperator splitst een lijst in de head en tail [1,2,3,4,5] = [H T]. H = 1, T = [2,3,4,5]
Recursie op lijsten Bewerking op elk element van een lijst Roep predicaat aan voor de head Recursie op de tail Basisgeval: meestal de lege lijst [] categorie(graan,voedsel). categorie(bos,locatie). categorie(zomer,periode). info([]). info([h T]) :- categorie(h,c), writeln(c=h), info(t).?- info([graan,bos,zomer]). voedsel=graan locatie=bos periode=zomer
Lijst als returnwaarde Resultaat van de berekening in een tweede lijst Met lijstoperator stap voor stap opbouwen resultaatlijst Basisgeval: twee lege lijsten categorie(graan,voedsel). categorie(bos,locatie). categorie(zomer,periode). info2([],[]). info2([h T],[C T2]) :- categorie(h,c), info2(t,t2).?- info2([graan,bos,zomer],l). L = [voedsel, locatie, periode].
Lijst als returnwaarde Een lijst-element kan bestaan uit verschillende gedeeltes categorie(graan,voedsel). categorie(bos,locatie). categorie(zomer,periode). info2([],[]). info2([h T],[C=H T2]) :- categorie(h,c), info2(t,t2).?- info2([graan,bos,zomer],l). L = [voedsel=graan, locatie=bos, periode=zomer].
Trace Prolog heeft een ingebouwde debugger: trace Volg stap voor stap wat een programma doet categorie(graan,voedsel). categorie(bos,locatie). info2([],[]). info2([h T],[C T2]) :- categorie(h,c), info2(t,t2). [trace]?- info2([graan,bos],l). Call: (7) info2([graan, bos], _G6169)? creep Call: (8) categorie(graan, _G6246)? creep Exit: (8) categorie(graan, voedsel)? creep Call: (8) info2([bos], _G6247)? creep Call: (9) categorie(bos, _G6249)? creep Exit: (9) categorie(bos, locatie)? creep Call: (9) info2([], _G6250)? creep Exit: (9) info2([], [])? creep Exit: (8) info2([bos], [locatie])? creep Exit: (7) info2([graan, bos], [voedsel, locatie])? creep L = [voedsel, locatie].
Ingebouwde lijstpredicaten Prolog heeft ingebouwde predicaten voor veelvoorkomende lijstoperaties Element in lijst: member Lijsten combineren en splitsen: append Lengte van een lijst: length Sorteren: sort
Ingebouwde lijstpredicaten Prolog heeft ingebouwde predicaten voor veelvoorkomende lijstoperaties Element in lijst: member Lijsten combineren en splitsen: append Lengte van een lijst: length Sorteren: sort?- member(2,[1,2,3]). true?- member(4,[1,2,3]). false?- member(x,[1,2,3]). X = 1; X = 2; X = 3?- append([1,2],[3,4],l). L = [1,2,3,4]?- append(l1,[3,4],[1,2,3,4]). L1 = [1,2]?- append(l1,l2,[1,2,3,4]). L1 = [], L2 = [1,2,3,4];?- length([a,b,c],x). X = 3.?- length(l,3). L = [_G6240, _G6243, _G6246].?- sort([3,2,4],s). S = [2,3,4]?- sort(l,[2,3,4]). ERROR: sort/2: Arguments are not sufficiently instantiated
Feiten en regels aanpassen Feiten en regels uit een bestand kunnen worden aangepast vanaf de prompt of vanuit de regels Predicaten assert en retract Volgorde: assert voegt onderaan toe, asserta voegt bovenaan toe Alleen voor dynamische feiten en regels Bekijk de huidige feiten en regels met listing(naam) :- dynamic eet/2. eet(muis,kaas). eet(kat,muis).?- assert(eet(muis,graan)).?- listing(eet). :- dynamic eet/2. eet(muis,kaas). eet(kat,muis). eet(muis,graan).?- retract(eet(x,graan)).
Definite Clause Grammars
Parsing in Prolog Prolog is ontwikkeld voor het verwerken van natuurlijke taal Definieer de grammatica als Prolog-regels Definieer het lexicon als Prolog-lijsten Geef als query de vraag of een stukje tekst voldoet aan de regels voor een bepaalde grammaticale constructie Voorbeeld: zin("marie ziet Jan") of zin("marie Jan ziet") (pseudo-code)
Parsing in Prolog Prolog is ontwikkeld voor het verwerken van natuurlijke taal Definieer de grammatica als Prolog-regels Definieer het lexicon als Prolog-lijsten Geef als query de vraag of een stukje tekst voldoet aan de regels voor een bepaalde grammaticale constructie Voorbeeld: zin("marie ziet Jan") of zin("marie Jan ziet") (pseudo-code) Dit is een regelgebaseerde aanpak Veel (succesvolle) methodes in taalverwerking maken gebruik van een statistische aanpak Hier is veel discussie over
Grammatica Grammatica s maken gebruik van categorieën Werkwoord, zelfstandig naamwoord, lidwoord Kleinere eenheden worden gebruikt om een grotere categorie te definiëren Voorbeeld lidwoord + zelfstandig naamwoord naamwoordgroep naamwoordgroep + werkwoord zin de + man naamwoordgroep de man + loopt zin Query: zin("de man loopt").
Categorieën Categorieën worden meestal weergegeven met (Engelse) afkortingen Vaak een phrase De man = noun phrase, np uscki.nl: je moeder is een noun phrase det determiner lidwoord de n noun naamwoord man pn proper noun eigennaam Jan pron pronoun voornaamwoord hij v verb werkwoord loopt adj adjective bijvoeglijk naamwoord (een) blauw (paard) adv adverb bijwoord (het paard is) blauw prep preposition voorzetsel in con conjuction voegwoord omdat np noun phrase naamgroep de kleine muis vp verb phrase werkwoordgroep ziet de man pp prepositional phrase voorzetselgroep in de zomer s sentence zin de muis eet kaas
Context-vrije grammatica Deze grammatica is context-vrij (context free, CFG) Een grammaticaregel wordt toegepast op een deel van de zin Als dit deel voldoet aan de categorieën en de volgorde kan de regel worden gebruikt De rest van de zin (de context) wordt buiten beschouwing gelaten voor deze regel Vergelijk: De man loopt op de weg, De man loopt hard Computationeel handige eigenschap
Context-vrije grammatica Deze grammatica is context-vrij (context free, CFG) Een grammaticaregel wordt toegepast op een deel van de zin Als dit deel voldoet aan de categorieën en de volgorde kan de regel worden gebruikt De rest van de zin (de context) wordt buiten beschouwing gelaten voor deze regel Vergelijk: De man loopt op de weg, De man loopt hard Computationeel handige eigenschap Voor natuurlijke talen is een context-vrije grammatica niet altijd handig Jan zag Marie Hans Prolog uitleggen Voor veel gevallen is een CFG wel geschikt
Definite Clause Grammar Een definite clause is een logische formule in een bepaalde vorm p q... r z 1 conclusie, een eindig aantal voorwaarden (definite) Prolog: z :- p, q, r. Grammatica in Prolog: definite clause grammar (DCG)
Syntax van DCG s Grammaticaregels worden gerepresenteerd met Prolog-regels Speciale notatie Gewone regel: conclusie :- voorwaardes. DCG-regel: structuur --> categorieën. Lexicon als regels met een lijst als voorwaarde categorie --> [woord]. s --> np, vp. np --> pn. vp --> v. pn --> [jan]. v --> [loopt]. % sentence = noun phrase + verb phrase % noun phrase = proper noun % verb phrase = verb
Queries in een DCG Direct met de categorie Twee argumenten: tekst en rest s --> np, vp. np --> pn. vp --> v. pn --> [jan]. v --> [loopt].?- s([jan,loopt],[]). true.?- s([loopt,jan],[]). false.?- np([jan],[]). true.?- np([jan,loopt],[]). false.?- np([jan,loopt],[loopt]). true.?- np([jan,loopt],rest). Rest = [loopt].
Queries in een DCG Ingebouwd: phrase/2 Argumenten: categorie en lijst met de zin Uitgebreider: phrase/3, met rest s --> np, vp. np --> pn. vp --> v. pn --> [jan]. v --> [loopt].?- phrase(s,[jan,loopt]). true.?- phrase(s,[jan,loopt],rest). Rest = [].?- phrase(np,[jan,loopt],rest). Rest = [loopt].?- phrase(vp,[jan,loopt],rest). false.
Meerdere mogelijkheden In het lexicon staan meerdere woorden met dezelfde categorie Voor veel niet-lexicale categorieën zijn ook meerdere regels Hierdoor zijn er veel verschillende combinaties (afleidingen) die een correcte structuur vormen s --> np, vp. np --> pn. np --> det, n. vp --> v, np. pn --> [marie]. v --> [ziet]. det --> [de]. n --> [man]. n --> [muis].?- s([marie,ziet,de,man],[]). true.?- s([marie,ziet,de,muis],[]). true.?- s([marie,ziet,muis],[]). false.?- s([de,muis,ziet,marie])). true.
Parsingstrategie DCG Prolog kijkt naar het begin van de lijst Het begin wordt gematcht met de eerste deelcategorie De rest wordt gebruikt voor de volgende deelcategorieën Wat na de laatste deelcategorie overblijft is de rest van de query
s --> np, vp. np --> pn. np --> det, n. vp --> v, np.?- s([marie,ziet,de,muis],[]). query: np([marie,ziet,de,muis],rest) query: pn([marie,ziet,de,muis],rest) pn = [marie] np = [marie], Rest = [ziet,de,muis] query: vp([ziet,de,muis],rest) query: v([ziet,de,muis],rest) v = [ziet], Rest = [de,muis] query: np([de,muis],rest) query: pn([de,muis],rest), fail nieuwe query: det([de,muis],rest) det = [de]. Rest = [muis] query: n([muis],rest) n=[muis], Rest = [] np = [de,muis], Rest = [] vp = [ziet,de,muis], Rest = [] s = [marie,ziet,de,muis], Rest = []
Parsingstrategie DCG Prolog kijkt naar het begin van de lijst Het begin wordt gematcht met de eerste deelcategorie De rest wordt gebruikt voor de volgende deelcategorieën Wat na de laatste deelcategorie overblijft is de rest van de query Vanwege deze strategie kan er achteraan de lijst iets overblijven Maar: vooraan of in het midden iets weglaten kan niet np([de,man,ziet], Rest) % goed np(begin,[ziet,de,man]) % fout!
Genereren Met de tekst als variabele kan je taalvoorbeelden genereren s --> np, vp. np --> pn. np --> det, n. vp --> v, np. pn --> [marie]. v --> [ziet]. det --> [de]. n --> [man]. n --> [muis].?- s(z,[]). Z = [marie, ziet, marie] ; Z = [marie, ziet, de, man] ; Z = [marie, ziet, de, muis] ; Z = [de, man, ziet, marie] ;...
Correcte zinnen Marie ziet Marie heeft een correcte structuur Introductie van informatie is wat ongebruikelijk Marie ziet zichzelf Voorwaarde: een naam mag in dergelijke gevallen maar 1 keer voorkomen Deze voorwaarde is niet context-vrij
Correcte zinnen Marie ziet Marie heeft een correcte structuur Introductie van informatie is wat ongebruikelijk Marie ziet zichzelf Voorwaarde: een naam mag in dergelijke gevallen maar 1 keer voorkomen Deze voorwaarde is niet context-vrij pn --> [marie] is alleen toegestaan als deze regel in de context nog niet is gebruikt Een gewone DCG kan deze voorwaarde niet implementeren Wel mogelijk in Prolog
DCG s en recursie In natuurlijke taal zit regelmatig herhaling Een grote rode vliegende luchtballon Herhaling in Prolog recursie det --> [een]. n --> [luchtballon]. adj --> [grote]. adj --> [rode]. adj --> [vliegende]. np --> det, n. np --> det, adj, n. np --> det, adj, adj, n. np --> det, adj, adj, adj, n.
DCG s en recursie In natuurlijke taal zit regelmatig herhaling Een grote rode vliegende luchtballon Herhaling in Prolog recursie det --> [een]. n --> [luchtballon]. adj --> [grote]. adj --> [rode]. adj --> [vliegende]. np --> det, ng. ng --> n. ng --> ag, n. ag --> ag, adj. ag --> adj.
DCG s en recursie In natuurlijke taal zit regelmatig herhaling Een grote rode vliegende luchtballon Herhaling in Prolog recursie det --> [een]. n --> [luchtballon]. adj --> [grote]. adj --> [rode]. adj --> [vliegende]. np --> det, ng. ng --> n. ng --> ag, n. ag --> ag, adj. ag --> adj. % oneindige recursie
DCG s en recursie In natuurlijke taal zit regelmatig herhaling Een grote rode vliegende luchtballon Herhaling in Prolog recursie det --> [een]. n --> [luchtballon]. adj --> [grote]. adj --> [rode]. adj --> [vliegende]. np --> det, ng. ng --> n. ng --> ag, n. ag --> adj. ag --> ag, adj. % beter
DCG s en recursie In natuurlijke taal zit regelmatig herhaling Een grote rode vliegende luchtballon Herhaling in Prolog recursie det --> [een]. n --> [luchtballon]. adj --> [grote]. adj --> [rode]. adj --> [vliegende]. np --> det, ng. ng --> n. ng --> ag, n. ag --> adj. ag --> adj, ag. % nog beter
DCG s en recursie In natuurlijke taal zit ook nesting De man zit op de bank in het park bij de rivier S(NP,VP(V,PP(NP(PP(NP(PP(NP))))))) Nesting in Prolog recursie S NP de man V zit PP PREP op NP NP de bank PP PREP in NP NP het park PREP bij PP NP de rivier
DCG s en recursie Nesting in Prolog recursie De man zit op de bank in het park bij de rivier s --> np, vp. np --> det, n. vp --> v, np. vp --> v, pp. np --> det, n, pp. pp --> prep, np. % np --> pp % pp --> np: recursie
DCG s en recursie Nesting in Prolog recursie De man loopt en de vrouw fietst s --> np, vp. np --> det, n. vp --> v. s --> s, con, s. con --> [en]. % fout: oneindige recursie
DCG s en recursie Nesting in Prolog recursie De man loopt en de vrouw fietst De man loopt en fietst en schaatst s --> np, vp. np --> det, n. vp --> v. vp --> v, con, vp. s --> s_simpel, con, s. s_simpel --> np, vp. con --> [en]. % eerst niet-recursief predicaat % extra niet-recursief predicaat % definitie gelijk aan s
DCG s met argumenten
Grammaticale overeenstemming Standaardcategorieën houden geen rekening met grammaticale eigenschappen np --> det,n. det --> [de]. det --> [het]. n --> [man]. n --> [huis].?- np(x,[]). X = [de, man] ; X = [de, huis] ; X = [het, man] ; X = [het, huis] ;
Grammaticale overeenstemming Mogelijke oplossing: aparte categorieën np --> mdet,mn. np --> odet,on. mdet --> [de]. odet --> [het]. mn --> [man]. on --> [huis].?- np(x,[]). X = [de, man] ; X = [het, huis] ;
Grammaticale overeenstemming Met aparte categorieën is er veel redundantie Beter: geef een argument mee aan de categorie np --> det(g),n(g). det(m) --> [de]. det(o) --> [het]. n(m) --> [man]. n(o) --> [huis].?- np(x,[]). X = [de, man] ; X = [het, huis] ;
Toepassing van argumenten Werkwoordsvormen Meervoud Persoonlijke voornaamwoorden Andere talen: naamvallen s --> np(p), vp(p). np(p) --> pron(p). vp(p) --> v(p). pron(1) --> [ik]. pron(2-3) --> [jij]. pron(2-3) --> [hij]. pron(4) --> [wij]. v(1) --> [loop]. v(2-3) --> [loopt]. v(4) --> [lopen].
Toepassing van argumenten Werkwoordsvormen Meervoud Persoonlijke voornaamwoorden Andere talen: naamvallen np --> det, n(m), pp(m). pp(m) --> prep, np(m). np(mv) --> n(mv). n(mv) --> [combinatie]. n(mv) --> [factoren]. n(ev) --> [krant]. n(ev) --> [gisteren]. prep --> [van]. det --> [een].
Toepassing van argumenten Werkwoordsvormen Meervoud Persoonlijke voornaamwoorden Andere talen: naamvallen s --> np(subj), vp(obj). np(n) --> pron(n). vp(n) --> v, np(n). pron(subj) --> [hij]. pron(subj) --> [zij]. pron(obj) --> [hem]. pron(obj) --> [haar]. v --> [ziet].
DCG s met returnwaardes
Argumenten als returnwaarde Een DCG met de tekst gegeven heeft als resultaat true of false Maar: onbekend hoe de parsing tot stand is gekomen Vaak is de structuur interessant Nodig voor automatische interpretatie van een zin Jan en Marie gaan morgen op vakantie Wie: Jan en Marie, subject-np Wat: vakantie, object-np in vp Wanneer: morgen, extra np in vp Of: omzetten van natuurlijke tekst in een Prolog-predicaat
Verzamelen van tussenresultaten Strategie: voeg bij interessante categorieën een argument toe Gebruik deze argumenten in de hoofdquery Neem een argument eventueel een paar niveaus mee s(a,b,c) --> np(a), vp(b,c). np(x) --> det, n(x). vp(x,_) --> v(x). vp(x,y) --> v(x), np(y). pn(marie) --> [marie]. pn(jan) --> [jan]. v(ziet) --> [ziet]. det --> [de]. n(man) --> [man]. n(muis) --> [muis].
Verzamelen van tussenresultaten De extra variabelen in de query komen vooraan s(a,b,c) --> np(a), vp(b,c). np(x) --> det, n(x). vp(x,_) --> v(x). vp(x,y) --> v(x), np(y). pn(marie) --> [marie]. pn(jan) --> [jan]. v(ziet) --> [ziet]. det --> [de]. n(man) --> [man]. n(muis) --> [muis].?- s(a,b,c,l,[]). A = man, B = ziet, C = muis L = [de, man, ziet, de, muis]
Van variabelen naar een predicaat Het ingebouwde predicaat =../2 zet een lijst om naar een predicaat en andersom Het eerste element van de lijst wordt de naam van het predicaat, de volgende elementen worden de argumenten van het predicaat Het ingebouwde predicaat call/1 voert een predicaat uit?- P =..[ziet,man,muis]. P = ziet(man, muis).?- eet(muis,kaas) =.. L. L = [eet,muis,kaas].?- call(eet(muis,x)). X = kaas.?- P =..[eet,muis,x], call(p). X = kaas.
Van strings naar lijsten Een DCG verwacht een lijst als invoer Niet handig voor de gebruiker Ingebouwd predicaat split string/4 zet een string om naar een lijst Ingebouwd predicaat read line to string/2 leest een stream (bijvoorbeeld de standaardinvoer van het toetsenbord) naar een string Let op: een atoom is niet hetzelfde als een string Gebruik in je DCG strings of gebruik een predicaat om een lijst strings om te zetten naar een lijst atomen
Van strings naar lijsten s --> np, vp. np --> pn. vp --> v. pn --> [marie]. v --> [loopt]. % atoom % atoom % user_input is het toetsenbord?- read_line_to_string(user_input,s). : marie loopt S = "marie loopt" % split_string(string,scheidingsteken,padding,lijst)?- read_line_to_string(user_input,s), split_string(s,,,l). : marie loopt S = "marie loopt" L = ["marie", "loopt"]
Van strings naar lijsten s --> np, vp. np --> pn. vp --> v. pn --> [marie]. v --> [loopt]. % atoom % atoom?- read_line_to_string(user_input,s), split_string(s,,,l), s(l,[]). : marie loopt false.
Van strings naar lijsten s --> np, vp. np --> pn. vp --> v. pn --> ["marie"]. v --> ["loopt"]. % string % string?- read_line_to_string(user_input,s), split_string(s,,,l), s(l,[]). : marie loopt S = "marie loopt" L = ["marie", "loopt"]
Van strings naar lijsten list_str_atom([],[]). list_str_atom([h T],[H2 T2]):- atom_string(h2,h), % ingebouwd predicaat list_str_atom(t,t2). s --> np, vp. np --> pn. vp --> v. pn --> [marie]. % atoom v --> [loopt]. % atoom?- read_line_to_string(user_input,s), split_string(s,,,l), list_str_atom(l,l2), s(l2,[]). : marie loopt S = "marie loopt" L = ["marie", "loopt"] L2 = [marie, loopt]