Die intuitive Antwort lautet: Wenn Sie keine unbegrenzten Schleifen haben und keine Rekursion haben und nicht gehen, werden Ihre Programme beendet. Dies ist nicht ganz richtig, es gibt andere Möglichkeiten, um die Nichtbeendigung einzuschleichen, aber es ist gut genug für die meisten praktischen Fälle. Natürlich ist die Umkehrung falsch, es gibt Sprachen mit diesen Konstrukten, die keine nicht terminierenden Programme zulassen, aber sie verwenden andere Arten von Einschränkungen, wie zum Beispiel hochentwickelte Typsysteme.
Rekursion
Eine häufige Einschränkung in Skriptsprachen besteht darin, eine Rekursion dynamisch zu verhindern: Wenn A aufruft, B aufruft, C aufruft, ... aufruft, gibt der Interpreter (oder in Ihrem Fall der Checker) auf oder signalisiert einen Fehler, selbst wenn die Rekursion tatsächlich beendet werden könnte. Zwei konkrete Beispiele:
Der C-Präprozessor lässt ein Makro intakt, während er dieses Makro erweitert. Am häufigsten wird ein Wrapper um eine Funktion definiert:
#define f(x) (printf("calling f(%d)\n", (x)), f(x))
f(3);
Dies erweitert sich zu
(printf("calling f(%d)\n", (3)), f(3))
Die gegenseitige Rekursion wird ebenfalls behandelt. Dies hat zur Folge, dass der C-Präprozessor immer beendet wird, obwohl Makros mit hoher Laufzeitkomplexität erstellt werden können.
#define f0(x) x(x)x(x)
#define f1(x) f0(f0(x))
#define f2(x) f1(f1(x))
#define f3(x) f2(f2(x))
f3(x)
Unix-Shells erweitern Aliase rekursiv, jedoch nur, bis sie auf einen Alias stoßen, der bereits erweitert wird. Wiederum besteht der Hauptzweck darin, einen Alias für einen Befehl mit ähnlichem Namen zu definieren.
alias ls='ls --color'
alias ll='ls -l'
nn
Es gibt allgemeinere Methoden, um zu beweisen, dass rekursive Aufrufe beendet werden, z. B. das Auffinden einer positiven Ganzzahl, die von einem rekursiven Aufruf zum nächsten immer abnimmt, die jedoch erheblich schwerer zu erkennen sind. Sie sind oft schwer zu überprüfen, geschweige denn abzuleiten.
Schleifen
for
mn
Insbesondere mit for-Schleifen (und sinnvollen Sprachkonstrukten wie Bedingungen) können Sie alle primitiven rekursiven Funktionen schreiben und umgekehrt. Sie können primitive rekursive Funktionen syntaktisch erkennen (wenn sie unverschlüsselt geschrieben sind), da sie keine while-Schleife oder goto oder recursion oder einen anderen Trick verwenden. Primitive rekursive Funktionen werden garantiert beendet, und die meisten praktischen Aufgaben gehen nicht über die primitive Rekursion hinaus.
Gilles 'SO - hör auf böse zu sein'
quelle