Ich arbeite durch "Learn Prolog jetzt" Online-Buch zum Spaß.Sollte ich die Tail-Rekursion in Prolog und generell vermeiden?
Ich versuche, ein Prädikat zu schreiben, das durch jedes Mitglied einer Liste geht und eines hinzufügt, das Akkumulatoren verwendet. Ich habe es schon ohne Schwanzrekursion gemacht.
Aber ich habe gelesen, dass es besser ist, diese Art der Rekursion aus Leistungsgründen zu vermeiden. Ist das wahr? Wird es als "gute Praxis" angesehen, die Tail Recursion immer zu verwenden? Wird es sich lohnen, Akkus zu benutzen, um eine gute Angewohnheit zu bekommen?
Ich habe versucht, dieses Beispiel in die Verwendung von Akkumulatoren zu ändern, aber es kehrt die Liste um. Wie kann ich das vermeiden?
accAddOne([X|Xs],Acc,Result) :- Xnew is X+1, accAddOne(Xs,[Xnew|Acc],Result).
accAddOne([],A,A).
addone(List,Result) :- accAddOne(List,[],Result).
implementieren ' addone' ist bereits vollständig tail-call-optimizable. Es ist [tail recursive * "modulo contra" *] (https://en.wikipedia.org/wiki/Tail_call#Tail_recursion_modulo_cons), und Prolog hat diese Optimierung - die neue Cons-Zelle '[Y | Ys]' ist * Zuerst * mit den zwei "Löchern" darin (zwei noch uninstantiierte Logvars, "Y" und "Ys") zugewiesen, dann wird "Y" innerhalb des Körpers der Regel instanziiert (durch "is/2") und dann * Der rekursive Aufruf instanziiert die logische Variable "Ys". Es besteht somit keine Notwendigkeit, von dem rekursiven Aufruf in den Körper dieser Regel zurückzukehren. –
LPN! Heutzutage gibt es ein ganzes Kapitel, um den Unterschied durch Beispiele zu zeigen. Meiner Kenntnis nach ist Prolog eine Tail Recursion-Optimierung und daher wünschenswert, weil sie N Schritte effektiv in N/2 umwandelt, indem sie nicht zurücktritt. LPN: http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlse20 Kapitel 5.3, Januar 2018. –