Lors de récentes discussions au travail, quelqu'un a évoqué une fonction de trampoline.
J'ai lu la description sur Wikipedia . Il suffit de donner une idée générale de la fonctionnalité, mais j'aimerais quelque chose d'un peu plus concret.
Avez-vous un simple extrait de code qui illustrerait un trampoline?
Réponses:
Il y a aussi le sens LISP de `` trampoline '' tel que décrit sur Wikipedia:
Disons que nous utilisons Javascript et que nous voulons écrire la fonction naïve de Fibonacci en continuation-pass-style. La raison pour laquelle nous ferions cela n'est pas pertinente - pour porter Scheme sur JS par exemple, ou pour jouer avec CPS que nous devons utiliser de toute façon pour appeler des fonctions côté serveur.
Donc, la première tentative est
Mais, exécuter ceci avec
n = 25
dans Firefox donne une erreur «Trop de récursivité!». Maintenant, c'est exactement le problème (l'optimisation des appels de queue manquante en Javascript) que le trampoline résout. Au lieu de faire un appel (récursif) à une fonction, laissez-nousreturn
une instruction (thunk) pour appeler cette fonction, à interpréter dans une boucle.la source
Permettez-moi d'ajouter quelques exemples de fonction factorielle implémentée avec des trampolines, dans différentes langues:
Scala:
Java:
C (malchanceux sans implémentation de grands nombres):
la source
if (n < 2) Done(product)
, SO ne m'a pas permis de modifier 1 symbole ...Je vais vous donner un exemple que j'ai utilisé dans un patch anti-triche pour un jeu en ligne.
J'avais besoin de pouvoir analyser tous les fichiers chargés par le jeu pour les modifier. Donc, le moyen le plus robuste que j'ai trouvé pour le faire était d'utiliser un trampoline pour CreateFileA. Ainsi, lorsque le jeu était lancé, je trouvais l'adresse de CreateFileA en utilisant GetProcAddress, puis je modifierais les premiers octets de la fonction et j'insérerais le code d'assemblage qui passerait à ma propre fonction "trampoline", où je ferais certaines choses, et alors je reviendrais à l'emplacement suivant dans CreateFile après mon code jmp. Être capable de le faire de manière fiable est un peu plus délicat que cela, mais le concept de base consiste simplement à accrocher une fonction, à la forcer à la rediriger vers une autre fonction, puis à revenir à la fonction d'origine.
Edit: Microsoft a un cadre pour ce type de chose que vous pouvez regarder. Détours appelés
la source
J'expérimente actuellement des moyens d'implémenter l'optimisation des appels de queue pour un interpréteur de schéma, et donc pour le moment j'essaie de déterminer si le trampoline serait faisable pour moi.
Si je comprends bien, il s'agit essentiellement d'une série d'appels de fonction exécutés par une fonction de trampoline. Chaque fonction est appelée un thunk et retourne l'étape suivante du calcul jusqu'à la fin du programme (suite vide).
Voici le premier morceau de code que j'ai écrit pour améliorer ma compréhension du trampoline:
résulte en:
la source
Voici un exemple de fonctions imbriquées:
compar
ne peut pas être une fonction externe, car elle utilisenbytes
, qui n'existe que pendant l'sort_bytes
appel. Sur certaines architectures, une petite fonction stub - le trampoline - est générée lors de l'exécution et contient l'emplacement de la pile de l' invocation actuelle desort_bytes
. Lorsqu'il est appelé, il saute aucompar
code, en passant cette adresse.Ce désordre n'est pas nécessaire sur les architectures comme PowerPC, où l'ABI spécifie qu'un pointeur de fonction est en fait un "gros pointeur", une structure contenant à la fois un pointeur vers le code exécutable et un autre pointeur vers des données. Cependant, sur x86, un pointeur de fonction n'est qu'un pointeur.
la source
Pour C, un trampoline serait un pointeur de fonction:
Edit: Des trampolines plus ésotériques seraient implicitement générés par le compilateur. Une de ces utilisations serait une table de saut. (Bien qu'il y en ait clairement plus compliqués, plus vous commencez à essayer de générer du code compliqué.)
la source
Maintenant que C # a des fonctions locales , le kata de codage du jeu de bowling peut être résolu avec élégance avec un trampoline:
La méthode
Game.RollMany
est appelée avec un certain nombre de rouleaux: généralement 20 rouleaux s'il n'y a pas de pièces de rechange ou de grèves.La première ligne appelle immédiatement la fonction de trampoline:
return Trampoline(1, 0, rs.ToList());
. Cette fonction locale parcourt récursivement le tableau rolls. La fonction locale (le trampoline) permet au parcours de démarrer avec deux valeurs supplémentaires: commencer parframe
1 et lersf
(résultat jusqu'ici) 0.Dans la fonction locale, il existe un opérateur ternaire qui gère cinq cas:
La poursuite de la traversée se fait en appelant à nouveau le trampoline, mais maintenant avec des valeurs mises à jour.
Pour plus d'informations, recherchez: " accumulateur de récursion de queue ". Gardez à l'esprit que le compilateur n'optimise pas la récursivité de queue. Aussi élégante que puisse être cette solution, ce ne sera probablement pas le jeûné.
la source
la source