Effizienz und Grammatiken
Effizienz
Differenzlisten Grammatiken
Effizienz
Differenzlisten Grammatiken
Effizienz im Allgemeinen
Ausführungszeit, Speichererfordernis
Die traditionelle Computerarchitektur ist nicht besonders passend für Prologs Programmausführung: beweisen einer Zielliste
Für praktische Applikationen ist die mangelnde Effizienz von Prolog dann bedeutsam,
(1) wenn die Grundlaufzeit des Programms hoch ist und das Programm öfter aufgerufen werden muss.
(2) wenn die Anwendung online ist und der Benutzer auf Terminierung warten muss
Vorteile von Prolog bezüglich Programmentwicklungszeiten:
symbolische, nicht-numerische Programmierung, strukturierte Datenobjekte und Relationen auf diesen.
→ aber heute auch viele Bibliotheken z.B. in Java Ausführungszeit, Speichererfordernis
Die traditionelle Computerarchitektur ist nicht besonders passend für Prologs Programmausführung: beweisen einer Zielliste
Für praktische Applikationen ist die mangelnde Effizienz von Prolog dann bedeutsam,
(1) wenn die Grundlaufzeit des Programms hoch ist und das Programm öfter aufgerufen werden muss.
(2) wenn die Anwendung online ist und der Benutzer auf Terminierung warten muss
Vorteile von Prolog bezüglich Programmentwicklungszeiten:
symbolische, nicht-numerische Programmierung, strukturierte Datenobjekte und Relationen auf diesen.
→ aber heute auch viele Bibliotheken z.B. in Java
Effizienz im Allgemeinen
Ausführungszeit: im Allgemeinen ist ein compiliertes Programm schneller als ein interpretiertes. Deshalb falls vorhanden für
zeitkritische Anwendungen compilierte Programme verwenden.
Daneben:
- Ordnung der Klauseln
- Prozedurale Steuerung durch den Cut Schließlich:
Oft kann der Algorithmus selbst entscheidend verbessert werden.
- Verbesserung der Sucheffizienz, indem unnötiges Backtracking vermieden wird, aussichtslose Alternativen so schnell wie möglich beenden
- Passendere Datenstrukturen verwenden um die Objekte des Programms zu repräsentieren, so dass Operationen möglichst effizient implementiert werden können.
- Caching mit assert
Ausführungszeit: im Allgemeinen ist ein compiliertes Programm schneller als ein interpretiertes. Deshalb falls vorhanden für
zeitkritische Anwendungen compilierte Programme verwenden.
Daneben:
- Ordnung der Klauseln
- Prozedurale Steuerung durch den Cut Schließlich:
Oft kann der Algorithmus selbst entscheidend verbessert werden.
- Verbesserung der Sucheffizienz, indem unnötiges Backtracking vermieden wird, aussichtslose Alternativen so schnell wie möglich beenden
- Passendere Datenstrukturen verwenden um die Objekte des Programms zu repräsentieren, so dass Operationen möglichst effizient implementiert werden können.
- Caching mit assert
Effizienz durch Anordnung
Beispiel 1: Verbesserung der Effizienz des 8-Damen Programms In der ersten Lösung wurden die Y-Koordinaten für jede Dame
festgelegt indem Integer zwischen eins und acht ausgewählt werden.
member(Y,[1,2,3,4,5,6,7,8]).
Also wird zunächst 1, dann 2 usw. ausprobiert.
Nachdem die Damen in aufeinanderfolgenden Spalten auf dem Brett angeordnet werden, muss gelten, dass zwei aufeinanderfolgende
Damen in vertikaler Richtung mindestens zwei Quadrate entfernt angeordnet werden müssen.
member(Y,[1,5,2,6,3,7,4,8]) verbessert die erste Lösung um Faktor 3-4
Beispiel 1: Verbesserung der Effizienz des 8-Damen Programms In der ersten Lösung wurden die Y-Koordinaten für jede Dame
festgelegt indem Integer zwischen eins und acht ausgewählt werden.
member(Y,[1,2,3,4,5,6,7,8]).
Also wird zunächst 1, dann 2 usw. ausprobiert.
Nachdem die Damen in aufeinanderfolgenden Spalten auf dem Brett angeordnet werden, muss gelten, dass zwei aufeinanderfolgende
Damen in vertikaler Richtung mindestens zwei Quadrate entfernt angeordnet werden müssen.
member(Y,[1,5,2,6,3,7,4,8]) verbessert die erste Lösung um Faktor 3-4
Effizienz durch Anordnung
Beispiel2: Map coloring Problem: markiere jedes Land einer
gegebenen Karte aus vier Farben, so dass keine benachbarten Länder in derselben Farbe markiert sind.
ngb(Land,Nachbarn).
ngb(albanien,[griechenland,mazedonien,serbien]
ngb(andora,[frankreich,spanien]).
…
Lösung: Liste von Paaren Land/Farbe [albanien/C1,andorra/C2,...]
Definiere ein Prädikat für colors(Länder_Farben_Liste)
Beispiel2: Map coloring Problem: markiere jedes Land einer
gegebenen Karte aus vier Farben, so dass keine benachbarten Länder in derselben Farbe markiert sind.
ngb(Land,Nachbarn).
ngb(albanien,[griechenland,mazedonien,serbien]
ngb(andora,[frankreich,spanien]).
…
Lösung: Liste von Paaren Land/Farbe [albanien/C1,andorra/C2,...]
Definiere ein Prädikat für colors(Länder_Farben_Liste)
Effizienz durch Anordnung
colors([]).
colors([Country/Color|Rest]):-
colors(Rest), member(Color,[gelb,blau,rot,grün]), not(member(Country1/Color,Rest), neighbor(Country,Country1)).
neighbor(Country,Country1):-
ngb(Country,Neighbours),
member(Country1,Neighbors).
colors([]).
colors([Country/Color|Rest]):-
colors(Rest), member(Color,[gelb,blau,rot,grün]), not(member(Country1/Color,Rest), neighbor(Country,Country1)).
neighbor(Country,Country1):-
ngb(Country,Neighbours),
member(Country1,Neighbors).
Effizienz durch Anordnung
Aufruf über Hilfsprädikat:
country(C) :- ngb(C,_).
?- setoff(Country/Color, country(Country),CountryColorList), colors(ContryColorList).
setoff kontruiert eine Liste für z.B. Europa nach den ngb-Fakten in der Datenbank mit Variablen für die Farben. colors-Ziel soll dann die Farben belegen.
Aufruf über Hilfsprädikat:
country(C) :- ngb(C,_).
?- setoff(Country/Color, country(Country),CountryColorList), colors(ContryColorList).
setoff kontruiert eine Liste für z.B. Europa nach den ngb-Fakten in der Datenbank mit Variablen für die Farben. colors-Ziel soll dann die Farben belegen.
Effizienz durch Anordnung
Ineffizienzproblem:
Staaten und die Country/Color-Liste sind alphabetisch arrangiert.
Kein Zusammenhang mit der geographischen Lage.
Zuweisungsprozess der Farben startet am Ende der Liste (Warum?).
Zuweisungsprozess ist unabhängig von der ngb-Relation (Warum?).
Die Farben werden also beginnend von einem Punkt auf der Karte weiter bei einem anderen usw zugewiesen.
Mehr oder weniger zufällig. Es kann sehr leicht passieren, dass für ein Land, das viele Nachbarn hat, alle 4 Farben schon verbraucht sind! Dann ist aufwändiges Backtracking notwendig.
Ineffizienzproblem:
Staaten und die Country/Color-Liste sind alphabetisch arrangiert.
Kein Zusammenhang mit der geographischen Lage.
Zuweisungsprozess der Farben startet am Ende der Liste (Warum?).
Zuweisungsprozess ist unabhängig von der ngb-Relation (Warum?).
Die Farben werden also beginnend von einem Punkt auf der Karte weiter bei einem anderen usw zugewiesen.
Mehr oder weniger zufällig. Es kann sehr leicht passieren, dass für ein Land, das viele Nachbarn hat, alle 4 Farben schon verbraucht sind! Dann ist aufwändiges Backtracking notwendig.
Effizienz durch Anordnung
Klar ist: die Effizienz hängt von der Ordnung ab, in der Ländern die Farbe zugewiesen wird. Intuitiv ist schon eine einfache Strategie besser als Random:
Starte mit einem Land mit vielen Nachbarn, dann dessen Nachbarn und der Nachbarn Nachbarn...
Klar ist: die Effizienz hängt von der Ordnung ab, in der Ländern die Farbe zugewiesen wird. Intuitiv ist schon eine einfache Strategie besser als Random:
Starte mit einem Land mit vielen Nachbarn, dann dessen Nachbarn und der Nachbarn Nachbarn...
Effizienz durch Anordnung
makelist Prädikat
ausgehend von einem Land, z.B. Deutschland, wird eine Liste mit allen Ländern erstellt, die Closed heisst. Jedes Land wird zunächst in eine andere Liste geschrieben, die Open heisst. Aus Open kommt das Land zu Closed, wenn seine Nachbarn aus nbg(Land, Nachbarn), auf Open geschrieben worden sind.
makelist Prädikat
ausgehend von einem Land, z.B. Deutschland, wird eine Liste mit allen Ländern erstellt, die Closed heisst. Jedes Land wird zunächst in eine andere Liste geschrieben, die Open heisst. Aus Open kommt das Land zu Closed, wenn seine Nachbarn aus nbg(Land, Nachbarn), auf Open geschrieben worden sind.
Effizienz durch Anordnung
makelist Prädikat
makelist(List) :- collect([germany],[],List).
collect([],Closed,Closed). %keine Kandidaten für Closed %rausschreiben auf List
collect([X|Open],Closed,List) :-
member(X,Closed), !, collect(Open,Closed,List).
%X schon gesammelt collect([X|Open],Closed,List) :-
ngb(X,Ngbs),
append(Ngbs,Open,Open1),
collect(Open1,[X|Closed],List).
makelist Prädikat
makelist(List) :- collect([germany],[],List).
collect([],Closed,Closed). %keine Kandidaten für Closed %rausschreiben auf List
collect([X|Open],Closed,List) :-
member(X,Closed), !, collect(Open,Closed,List).
%X schon gesammelt collect([X|Open],Closed,List) :-
ngb(X,Ngbs),
append(Ngbs,Open,Open1),
collect(Open1,[X|Closed],List).
Differenzlisten
Verbesserung der Effizienz der Listenkonkatenation mithilfe von Differenzlisten
Programm zur Konkatenation von Listen bislang war:
append([],L,L).
append([X|L1],L2,[X|L3]):- append(L1,L2,L3).
Ineffizient, wenn die erste Liste lang ist.
Verbesserung der Effizienz der Listenkonkatenation mithilfe von Differenzlisten
Programm zur Konkatenation von Listen bislang war:
append([],L,L).
append([X|L1],L2,[X|L3]):- append(L1,L2,L3).
Ineffizient, wenn die erste Liste lang ist.
Differenzlisten
Beispiel: ?- append([a,b,c], [d,e],L).
Zielsequenz
append([a,b,c], [d,e],L)
append([b,c], [d,e],L') mit L = [a|L']
append([c], [d,e],L'') mit L' = [b|L'']
append([], [d,e],L''') mit L'' = [c|L''']
true mit L''' = [d,e]
Das append prädikat arbeitet die gesamte erste Liste ab, bis endlich die Leere Liste erreicht ist, dann beginnt der rekursive
Zusammenbau.
Beispiel: ?- append([a,b,c], [d,e],L).
Zielsequenz
append([a,b,c], [d,e],L)
append([b,c], [d,e],L') mit L = [a|L']
append([c], [d,e],L'') mit L' = [b|L'']
append([], [d,e],L''') mit L'' = [c|L''']
true mit L''' = [d,e]
Das append prädikat arbeitet die gesamte erste Liste ab, bis endlich die Leere Liste erreicht ist, dann beginnt der rekursive
Zusammenbau.
Differenzlisten
Beispielimplementierung von append mit Akkumulator Beispiel: ?- append_acc([a,b,c], [d,e],L).
Zielsequenz
append_acc([],L,L).
append_acc([X|Rest],Acc,L):- append_acc(Rest,[X|Acc],L).
L=[c,b,a,d,e].
Schon effizienter aber die erste Liste wird in umgekehrter Reihenfolge angehängt.
Beispielimplementierung von append mit Akkumulator Beispiel: ?- append_acc([a,b,c], [d,e],L).
Zielsequenz
append_acc([],L,L).
append_acc([X|Rest],Acc,L):- append_acc(Rest,[X|Acc],L).
L=[c,b,a,d,e].
Schon effizienter aber die erste Liste wird in umgekehrter Reihenfolge angehängt.
Differenzlisten
Was wir uns wünschen würden:
Skip das Scannen der ersten Liste und hänge die zweite Liste an, ohne die gesammte erste Liste abzuarbeiten.
Wir müssen wissen, wo das Ende einer Liste ist → wir brauchen eine andere Repräsentation von Listen.
Die Lösung wird als Differenzlisten bezeichnet.
Eine Differenzliste wird als Listenpaar repräsentiert.
L = [a,b,c] kann mit L1=[a,b,c,d,e] und L2= [d,e] als L1-L2 repräsentiert werden.
Achtung: nur wenn L2 ein Suffix von L1 ist!!!
Was wir uns wünschen würden:
Skip das Scannen der ersten Liste und hänge die zweite Liste an, ohne die gesammte erste Liste abzuarbeiten.
Wir müssen wissen, wo das Ende einer Liste ist → wir brauchen eine andere Repräsentation von Listen.
Die Lösung wird als Differenzlisten bezeichnet.
Eine Differenzliste wird als Listenpaar repräsentiert.
L = [a,b,c] kann mit L1=[a,b,c,d,e] und L2= [d,e] als L1-L2 repräsentiert werden.
Achtung: nur wenn L2 ein Suffix von L1 ist!!!
Differenzlisten
Dieselbe Liste kann von verschiedenen Differenzpaaren repräsentiert werden.
[a,b,c] - [ ]
[a,b,c,d,e] - [d,e]
[a,b,c,d,e|T] - [d,e|T]
[a,b,c|T] – T
wobei T eine beliebige Liste ist.
Die leere Liste wird durch irgendein Paar der Form L-L als Differenzliste repräsentiert.
Dieselbe Liste kann von verschiedenen Differenzpaaren repräsentiert werden.
[a,b,c] - [ ]
[a,b,c,d,e] - [d,e]
[a,b,c,d,e|T] - [d,e|T]
[a,b,c|T] – T
wobei T eine beliebige Liste ist.
Die leere Liste wird durch irgendein Paar der Form L-L als Differenzliste repräsentiert.
Differenzlisten
Nachdem nun die zweite Liste im Paar das Ende der Liste
repräsentiert, ist das Ende direkt zugänglich. Dies kann für eine effiziente Implementation der Konkatenation ausgenutzt werden.
append_diff(As-Bs,Bs-Cs,As-Cs).
Anwendung: konkateniere [a,b,c] und [d,e].
Also [a,b,c|Bs] – Bs, [d,e|Cs] – Cs über den Aufruf
?- append_diff([a,b,c|Bs] – Bs,[d,e|Cs] – Cs,L - []) Cs = [ ]
Bs = [d,e|[]]
und damit L = [a,b,c,d,e|[]]
wichtig daran ist der Zusammenbau von As in L durch Unifikation indem Bs instantiert ist. Es wird Cs mit [] aufgerufen kann man
das Ergebnis weiter verarbeiten.
Nachdem nun die zweite Liste im Paar das Ende der Liste
repräsentiert, ist das Ende direkt zugänglich. Dies kann für eine effiziente Implementation der Konkatenation ausgenutzt werden.
append_diff(As-Bs,Bs-Cs,As-Cs).
Anwendung: konkateniere [a,b,c] und [d,e].
Also [a,b,c|Bs] – Bs, [d,e|Cs] – Cs über den Aufruf
?- append_diff([a,b,c|Bs] – Bs,[d,e|Cs] – Cs,L - []) Cs = [ ]
Bs = [d,e|[]]
und damit L = [a,b,c,d,e|[]]
wichtig daran ist der Zusammenbau von As in L durch Unifikation indem Bs instantiert ist. Es wird Cs mit [] aufgerufen kann man
das Ergebnis weiter verarbeiten.
Kontextfreie Grammatiken in Prolog
Kontextfreie Grammatik Pseudocode s → np vp
np → det n vp → v np | v det → der | das
n → Programmierer | Programm v → steht | schrieb
Kontextfreie Grammatik Pseudocode s → np vp
np → det n vp → v np | v det → der | das
n → Programmierer | Programm v → steht | schrieb
Übersetzung in Prolog
S(S) :- append(NP,VP,S), np(NP),
vp(VP).
wir zerteilen den Eingabesatz S eine Liste von Prolog-Atomen in zwei Teillisten und prüfen ob diese die Eigenschaft np und vp haben
S(S) :- append(NP,VP,S), np(NP),
vp(VP).
wir zerteilen den Eingabesatz S eine Liste von Prolog-Atomen in zwei Teillisten und prüfen ob diese die Eigenschaft np und vp haben
Übersetzung in Prolog
np(NP) :- append(D,N,NP), det(D),n(N).
vp(VP) :- append(V,NP,VP), v(V),np(NP).
vp(VP) :- v(VP).
det([der]).
det([das]).
n(['Programmierer']).
n(['Programm']).
v([steht]).
v([schrieb]).
np(NP) :- append(D,N,NP), det(D),n(N).
vp(VP) :- append(V,NP,VP), v(V),np(NP).
vp(VP) :- v(VP).
det([der]).
det([das]).
n(['Programmierer']).
n(['Programm']).
v([steht]).
v([schrieb]).
Übersetzung in Prolog
Aufruf des Programms:
[trace] ?- np([das,'Programm']).
Call: (6) np([das, 'Programm']) ? creep
Call: (7) append(_G1595, _G1596, [das, 'Programm']) ? creep Exit: (7) append([], [das, 'Programm'], [das, 'Programm']) ? creep Call: (7) det([]) ? creep
Fail: (7) det([]) ? creep
Exit: (7) append([das], ['Programm'], [das, 'Programm']) ? creep Call: (7) det([das]) ? creep
Exit: (7) det([das]) ? creep
Call: (7) n(['Programm']) ? creep Exit: (7) n(['Programm']) ? creep
Exit: (6) np([das, 'Programm']) ? creep true .
Problem zu viele append Aufrufe.
Aufruf des Programms:
[trace] ?- np([das,'Programm']).
Call: (6) np([das, 'Programm']) ? creep
Call: (7) append(_G1595, _G1596, [das, 'Programm']) ? creep Exit: (7) append([], [das, 'Programm'], [das, 'Programm']) ? creep Call: (7) det([]) ? creep
Fail: (7) det([]) ? creep
Exit: (7) append([das], ['Programm'], [das, 'Programm']) ? creep Call: (7) det([das]) ? creep
Exit: (7) det([das]) ? creep
Call: (7) n(['Programm']) ? creep Exit: (7) n(['Programm']) ? creep
Exit: (6) np([das, 'Programm']) ? creep true .
Problem zu viele append Aufrufe.
Übersetzung in Prolog
Lösung: Differenzlisten. Wir parsen den Satz entlang von links nach rechts. Wir können also sagen, Eingabe ist eine Liste von Atomen, von denen mit der ersten Regel np ein Teil NP abgearbeitet wird und dann bleibt noch ein Teil VP übrig. Wird mit vp der Teil VP
abgearbeitet, so bleibt nichts mehr übrig. Zugleich gilt: S = NP+VP wir erinnern uns an die Differenzlistenimplementierung.
appendl(As-Bs,Bs-Cs,As-Cs).
Damit wird NP: S – VP VP: VP - [ ]
Aufruf: S- [ ]
Lösung: Differenzlisten. Wir parsen den Satz entlang von links nach rechts. Wir können also sagen, Eingabe ist eine Liste von Atomen, von denen mit der ersten Regel np ein Teil NP abgearbeitet wird und dann bleibt noch ein Teil VP übrig. Wird mit vp der Teil VP
abgearbeitet, so bleibt nichts mehr übrig. Zugleich gilt: S = NP+VP wir erinnern uns an die Differenzlistenimplementierung.
appendl(As-Bs,Bs-Cs,As-Cs).
Damit wird NP: S – VP VP: VP - [ ]
Aufruf: S- [ ]
Übersetzung in Prolog
Neue Grammatikregeln:
s(S-[]) :-
appendl(S-VP,VP-[ ],S-[]), beginnt_mit_np(S-VP), beginnt_mit_vp(VP-[]).
Neue Grammatikregeln:
s(S-[]) :-
appendl(S-VP,VP-[ ],S-[]), beginnt_mit_np(S-VP), beginnt_mit_vp(VP-[]).
Übersetzung in Prolog
Vereinfacht ohne Append mit zwei Argumenten: Eingabeliste des Prädikats und Ausgaberestliste.
s(I,J) :- beginnt_mit_np(I,K),beginnt_mit_vp(K,J).
mit J = [ ] aufgerufen, dann wird der ganze Satz in der Liste
I=['Der','Programmierer',programmiert] abgearbeitet wenn J mit []
zurückkommt.
beginnt_mit_np(I,K) :- det(I,J), n(J,K).
beginnt_mit_vp(K,J) :- v(K,J).
Terminale:
det(I,J) :- I = [der|J].
det(I,J) :- I = ['Der'|J].
n(I,J) :- I = ['Programmierer'|J].
v(I,J) :- I = [programmiert|J].
Vereinfacht ohne Append mit zwei Argumenten: Eingabeliste des Prädikats und Ausgaberestliste.
s(I,J) :- beginnt_mit_np(I,K),beginnt_mit_vp(K,J).
mit J = [ ] aufgerufen, dann wird der ganze Satz in der Liste
I=['Der','Programmierer',programmiert] abgearbeitet wenn J mit []
zurückkommt.
beginnt_mit_np(I,K) :- det(I,J), n(J,K).
beginnt_mit_vp(K,J) :- v(K,J).
Terminale:
det(I,J) :- I = [der|J].
det(I,J) :- I = ['Der'|J].
n(I,J) :- I = ['Programmierer'|J].
v(I,J) :- I = [programmiert|J].
Übersetzung in Prolog
Startaufrufe und Abarbeitung Determinator
[trace] ?- s(['Der','Programmierer',programmiert],[]).
Call: (6) s(['Der', 'Programmierer', programmiert], []) ? creep
Call: (7) np(['Der', 'Programmierer', programmiert], _G138943) ? creep Call: (8) det(['Der', 'Programmierer', programmiert], _G138943) ? creep Call: (9) ['Der', 'Programmierer', programmiert]=[der|_G138939] ? creep Fail: (9) ['Der', 'Programmierer', programmiert]=[der|_G138939] ? creep Redo: (8) det(['Der', 'Programmierer', programmiert], _G138943) ? creep Call: (9) ['Der', 'Programmierer', programmiert]=['Der'|_G138939] ? creep
Exit: (9) ['Der', 'Programmierer', programmiert]=['Der', 'Programmierer', programmiert] ? creep
Exit: (8) det(['Der', 'Programmierer', programmiert], ['Programmierer', programmiert]) ? creep
Startaufrufe und Abarbeitung Determinator
[trace] ?- s(['Der','Programmierer',programmiert],[]).
Call: (6) s(['Der', 'Programmierer', programmiert], []) ? creep
Call: (7) np(['Der', 'Programmierer', programmiert], _G138943) ? creep Call: (8) det(['Der', 'Programmierer', programmiert], _G138943) ? creep Call: (9) ['Der', 'Programmierer', programmiert]=[der|_G138939] ? creep Fail: (9) ['Der', 'Programmierer', programmiert]=[der|_G138939] ? creep Redo: (8) det(['Der', 'Programmierer', programmiert], _G138943) ? creep Call: (9) ['Der', 'Programmierer', programmiert]=['Der'|_G138939] ? creep
Exit: (9) ['Der', 'Programmierer', programmiert]=['Der', 'Programmierer', programmiert] ? creep
Exit: (8) det(['Der', 'Programmierer', programmiert], ['Programmierer', programmiert]) ? creep
Übersetzung in Prolog
Abarbeitung Nomen schließen Nominalphrase np
[trace]
Call: (8) n(['Programmierer', programmiert], _G139255) ? creep
Call: (9) ['Programmierer', programmiert]=['Programmierer'|_G139251] ? creep Exit: (9) ['Programmierer', programmiert]=['Programmierer', programmiert] ? creep Exit: (8) n(['Programmierer', programmiert], [programmiert]) ? creep
Exit: (7) np(['Der', 'Programmierer', programmiert], [programmiert]) ? creep
Abarbeitung Nomen schließen Nominalphrase np
[trace]
Call: (8) n(['Programmierer', programmiert], _G139255) ? creep
Call: (9) ['Programmierer', programmiert]=['Programmierer'|_G139251] ? creep Exit: (9) ['Programmierer', programmiert]=['Programmierer', programmiert] ? creep Exit: (8) n(['Programmierer', programmiert], [programmiert]) ? creep
Exit: (7) np(['Der', 'Programmierer', programmiert], [programmiert]) ? creep
Übersetzung in Prolog
Abarbeitung verb/schließen Verbalphrase vp
[trace]
Call: (7) vp([programmiert], []) ? creep Call: (8) v([programmiert], []) ? creep
Call: (9) [programmiert]=[programmiert] ? creep Exit: (9) [programmiert]=[programmiert] ? creep Exit: (8) v([programmiert], []) ? creep
Exit: (7) vp([programmiert], []) ? creep
Exit: (6) s(['Der', 'Programmierer', programmiert], []) ? creep true
Abarbeitung verb/schließen Verbalphrase vp
[trace]
Call: (7) vp([programmiert], []) ? creep Call: (8) v([programmiert], []) ? creep
Call: (9) [programmiert]=[programmiert] ? creep Exit: (9) [programmiert]=[programmiert] ? creep Exit: (8) v([programmiert], []) ? creep
Exit: (7) vp([programmiert], []) ? creep
Exit: (6) s(['Der', 'Programmierer', programmiert], []) ? creep true
Übersetzung in Prolog
Tatsächlich erfolgt die Abarbeitung der Differenzlisten auf der Ebene der Terminale über den Restlistenoperator.
Alternative Schreibung der Terminale:
Eingabeliste mit dem Terminal in Atomform als Kopf Ausgabeliste ist der Rest.
det([der|J],J).
Dieser Rest ist dann wiederum Eingabeliste für das n Goal aus der np Regel
n([Programmierer|J],J).
Dieser Rest wird dann an die np als deren Ausgabeliste weitergegeben, der Rest vom Satz
np(I,J) :- det(I,K),n(K,J).
Tatsächlich erfolgt die Abarbeitung der Differenzlisten auf der Ebene der Terminale über den Restlistenoperator.
Alternative Schreibung der Terminale:
Eingabeliste mit dem Terminal in Atomform als Kopf Ausgabeliste ist der Rest.
det([der|J],J).
Dieser Rest ist dann wiederum Eingabeliste für das n Goal aus der np Regel
n([Programmierer|J],J).
Dieser Rest wird dann an die np als deren Ausgabeliste weitergegeben, der Rest vom Satz
np(I,J) :- det(I,K),n(K,J).
Übersetzung in Prolog
Format der Klauselgrammatiken in Prolog
In Prolog wird die Regelübersetzung von Grammatikklauseln in das notwendige Abarbeitungsformat durch das Prädikat
--> /2 erreicht.
Format der Klauselgrammatiken in Prolog
In Prolog wird die Regelübersetzung von Grammatikklauseln in das notwendige Abarbeitungsformat durch das Prädikat
--> /2 erreicht.
Übersetzung in Prolog
Unsere Beispielgrammatik als DCG:
s --> np,vp.
np --> det,n.
vp --> v, np.
vp --> v.
det --> [der].
det --> [das].
n --> ['Programmierer'].
n --> ['Programm'].
v --> [steht].
v --> [schrieb].
Diese Regeln werden dann intern in die Differenzlistenform übersetzt: np(I,J) :- det(I,K),n(K,J).
Unsere Beispielgrammatik als DCG:
s --> np,vp.
np --> det,n.
vp --> v, np.
vp --> v.
det --> [der].
det --> [das].
n --> ['Programmierer'].
n --> ['Programm'].
v --> [steht].
v --> [schrieb].
Diese Regeln werden dann intern in die Differenzlistenform übersetzt: np(I,J) :- det(I,K),n(K,J).
Hausaufgabe
Lesen Leiss-Skript zu Kapitel 6 DCG Lesen Bratko Kapitel 21
Lesen Leiss-Skript zu Kapitel 6 DCG Lesen Bratko Kapitel 21