V. Programme als Daten: Metainterpretation
- Metainterpretation
- Einfache Metainterpretierer
- All-Antwort- und Systemprädikate berücksichtigen
- Metainterpretierer zur Darstellung von Beweisbäumen für "reines PROLOG"
- Behandlung von
cut
© 2001
François Bry
Dieses Lehrmaterial wird ausschließlich zur privaten Verwendung
angeboten. Eine nichtprivate Nutzung (z.B. im Unterricht oder eine
Veröffentlichung von Kopien oder Übersetzungen) dieses Lehrmaterials
bedarf der Erlaubnis des Autors.
cut
p(a, f(b))
p
sowohl als Relations- als auch als Funktionssymbol
angesehen werden. Die Interpretation von p
als Relations- oder
Funktionssymbol hängt lediglich davon ab, wo der Ausdruck
p(a, f(b))
sich im Programm befindet. In
:- p(a, f(a, b)).
q(a) :- p(a, f(a, b)), s(a, b).
p(a, f(a, b)) :- r(a, b), s(a, b).
p
als Relationssymbol. In
q(p(a, f(a, b)), c).
q(a, b) :- r(p(a, f(a, b)), c).
p
als Funktionssymbol.
demo(X) :- X.
demo(true) :- !.
demo( (X,Y) ) :- !, demo(X), demo(Y).
demo(X) :- clause(X, Rumpf), demo(Rumpf).
clause
auf Klauseln, d.h. Fakten und Regeln, anwenden zu können,
das durch diese Klauseln definierte Relationssymbol als dynamisch deklariert
worden sein.
Programm P46 hat den Nachteil, baumrekursiv zu sein. Baumrekursive Programme sind in der Regel weniger effizient als linearrekursive Programme. Zudem verhindert die Baumrekursion die Anwendung der Endrekursion-Optimierung, die in den meisten PROLOG-Systemen durchgeführt wird und linear endrekursive Programme als iterative Prozesse ausführt.
Programm P47 ist ein linear endrekursives Gegenstück zu Programm P46, das allerdings eine etwas andere Anfrage- und Klauseldarstellung voraussetzt als die in PROLOG übliche.
:- op(255, xfx, <---).
demo([]).
demo([Atom | Anfragen]) :- (Atom <--- Rumpf),
append(Rumpf, Anfragen, NeueAnfragen),
demo(NeueAnfragen).
Kopf <--- Rumpf
Kopf
ein Atom ist
und Rumpf
eine Liste von Atomen ist.
Fakten werden als solche Klauseln dargestellt,
deren Rumpf, oder rechter Teil, die leere Liste ist.
Programm P47 wertet Anfragen aus,
die die Gestalt von Listen von Atomen haben, wobei die leere Liste als das
Atom true
interpretiert wird:
:- [user].
t(A, B) <--- [r(A, B)].
t(A, B) <--- [r(A, C), t(C, B)].
r(1, 2) <--- [].
r(2, 3) <--- [].
r(3, 4) <--- [].
yes.
:- findall(t(A, B), demo([t(A, B)]), L).
A = A
B = B
L = [t(1,2), t(2,3), t(3,4), t(1,3), t(1,4), t(2,4)]
yes.
:-
demo(true) :- !.
demo( (X,Y) ) :- !, demo(X), demo(Y).
demo(findall(X, Y, Z)) :- !, findall(X, demo(Y), Z).
demo(X^A) :- !, X^demo(A).
demo(bagof(X, Y, Z)) :- !, bagof(X, demo(Y), Z).
demo(coverof(X, Y, Z)) :- !, coverof(X, demo(Y), Z).
demo(setof(X, Y, Z)) :- !, setof(X, demo(Y), Z).
demo(X) :- system(X), !, X.
demo(X) :- clause(X, Rumpf), demo(Rumpf).
:- op(120, xfy, <--).
demo(true, true) :- !.
demo((X,Y), (BeweisX,BeweisY)) :- !, demo(X,BeweisX), demo(Y,BeweisY).
demo(X, (X <-- BeweisR)) :- clause(X, R), demo(R, BeweisR).
darstellen(Baum) :- darstellen(Baum, 0).
darstellen( (X <-- true), E) :- !, einruecken(E), write(X), nl.
darstellen( (X, Y), E) :- !, darstellen(X, E),
einruecken(E), write("und"), nl,
darstellen(Y, E).
darstellen( (X <-- Y), E) :- einruecken(E), write(X),
write(" weil"), nl,
Eplus1 is E + 1, darstellen(Y, Eplus1).
einruecken(0) :- !.
einruecken(E) :- write(" "), Eminus1 is E - 1, einruecken(Eminus1).
:- dynamic(kante/2), dynamic(verbunden/2).
:- [user].
kante(a, b1).
kante(b1, c1).
kante(b1, c2).
kante(a, b2).
kante(b2, c1).
kante(c1, a).
verbunden(X, Y) :- kante(X, Y).
verbunden(X, Y) :- kante(X, Z), verbunden(Z, Y).
yes.
:- demo(verbunden(a,a), B), darstellen(B).
verbunden(a, a) weil
kante(a, b1)
und
verbunden(b1, a) weil
kante(b1, c1)
und
verbunden(c1, a) weil
kante(c1, a)
B = verbunden(a, a) <--
(kante(a, b1) <-- true,
verbunden(b1, a) <--
(kante(b1, c1) <-- true,
verbunden(c1, a) <--
kante(c1, a) <-- true)) More?
B
wurde hier
zur besseren Verständlichkeit mit Einrückungen versehen,
die den Einrückungen bei der Ausgabe von darstellen(B)
entsprechen.
Das Prolog-System gibt den Wert von B
natürlich ohne Einrückungen aus.
cut
demo(true) :- !.
demo(!) :- !.
demo( (X,Y) ) :- !, demo(X), demo(Y).
demo(X) :- clause(X, Rumpf), demo(Rumpf).
:- dynamic(p/1).
yes.
:- [user].
p(1).
p(2).
p(3).
yes.
:- p(A), !.
A = 1
yes.
:- demo( (p(A), !) ).
A = 1 More? (;) ;
A = 2 More? (;) ;
A = 3
yes.
:-
demo(!) :- !.
behandelt
eigentlich das Cut wie true
, d. h. hat nicht den gewünschten
Effekt. Die Anfrage
demo( (p(A), !) ).
demo(p(A)), demo(!).
demo(p(A)), demo(true).
demo(p(A)).
demo(X) :- demo(X, M), ( M == cut_rueck, !, fail
; true ).
demo(_, M) :- M == cut_rueck, !, fail.
demo(!, _).
demo(!, cut_rueck) :- !.
demo(true, _) :- !.
demo((X,Y), M) :- !, demo(X, M), ( M == cut_rueck, !
; demo(Y, M) ).
demo(X, M) :- clause(X, Rumpf),
demo(Rumpf, M), ( M == cut_rueck, !, fail
; true ).
:- dynamic(p/1).
yes.
:- [user].
p(1).
p(2).
p(3).
yes.
:- demo( (p(A),!), M ).
A = 1
M = M More? (;) ;
A = 1
M = cut_rueck More? (;) ;
A = 2
M = M More? (;) ;
A = 2
M = cut_rueck More? (;) ;
A = 3
M = M More? (;) ;
A = 3
M = cut_rueck
yes.
:- demo( (p(A),!) ).
A = 1 More? (;) ;
no (more) solution.
:- dynamic(p/1), dynamic(q/1),
dynamic(r/1), dynamic(s/1), dynamic(t/1).
yes.
:- [user].
p(Z) :- q(Z).
p(Z) :- t(Z).
q(Z) :- r(Z), !.
q(Z) :- s(Z).
r(1).
r(2).
s(3).
s(4).
t(a).
t(b).
yes.
:- demo( p(Z) ).
Z = 1 More? (;) ;
Z = a More? (;) ;
Z = b
yes.
demo/1
sowie in
der ersten und letzten Klausel von demo/2
wird !,fail
statt not
verwendet, um ein unerwünschtes Rücksetzen über die Disjunktion zu
vermeiden.
Man überprüfe, warum die folgende Definition von demo/1
nicht das Gewünschte leisten würde:demo(X) :- demo(X,M), M \== cut_rueck.
Letzte Änderung: 18. August 1998