Durante discusiones recientes en el trabajo, alguien se refirió a una función de trampolín.
He leído la descripción en Wikipedia . Es suficiente para dar una idea general de la funcionalidad, pero me gustaría algo un poco más concreto.
¿Tiene un simple fragmento de código que ilustraría un trampolín?
Respuestas:
También existe el sentido LISP de 'trampolín' como se describe en Wikipedia:
Digamos que estamos usando Javascript y queremos escribir la función de Fibonacci ingenua en estilo de continuación-paso. La razón por la que haríamos esto no es relevante: para portar Scheme a JS, por ejemplo, o para jugar con CPS, que tenemos que usar de todos modos para llamar a las funciones del lado del servidor.
Entonces, el primer intento es
Pero, ejecutar esto con
n = 25
en Firefox da un error '¡Demasiada recursividad!'. Ahora bien, este es exactamente el problema (falta la optimización de la llamada de cola en Javascript) que resuelve el trampolín. En lugar de hacer una llamada (recursiva) a una función, permítanosreturn
una instrucción (thunk) para llamar a esa función, para ser interpretada en un bucle.fuente
Permítanme agregar algunos ejemplos de función factorial implementada con trampolines, en diferentes idiomas:
Scala:
Java:
C (mala suerte sin la implementación de grandes números):
fuente
if (n < 2) Done(product)
, SO no me permitió editar 1 símbolo ...Les daré un ejemplo que utilicé en un parche anti-trampas para un juego en línea.
Necesitaba poder escanear todos los archivos que el juego cargaba para modificarlos. Entonces, la forma más sólida que encontré para hacer esto fue usar un trampolín para CreateFileA. Entonces, cuando se lanzaba el juego, encontraba la dirección para CreateFileA usando GetProcAddress, luego modificaba los primeros bytes de la función e insertaba el código ensamblador que saltaba a mi propia función de "trampolín", donde haría algunas cosas, y luego volvería a la siguiente ubicación en CreateFile después de mi código jmp. Poder hacerlo de manera confiable es un poco más complicado que eso, pero el concepto básico es simplemente conectar una función, forzarla a redirigirla a otra función y luego volver a la función original.
Editar: Microsoft tiene un marco para este tipo de cosas que puedes ver. Desvíos llamados
fuente
Actualmente estoy experimentando formas de implementar la optimización de la llamada de cola para un intérprete de Scheme, por lo que en este momento estoy tratando de averiguar si el trampolín sería factible para mí.
Según tengo entendido, es básicamente una serie de llamadas de función realizadas por una función de trampolín. Cada función se llama procesador y devuelve el siguiente paso en el cálculo hasta que el programa termina (continuación vacía).
Aquí está el primer fragmento de código que escribí para mejorar mi comprensión del trampolín:
resulta en:
fuente
Aquí tienes un ejemplo de funciones anidadas:
compar
no puede ser una función externa, porque usanbytes
, que solo existe durante lasort_bytes
llamada. En algunas arquitecturas, una pequeña función de código auxiliar, el trampolín, se genera en tiempo de ejecución y contiene la ubicación de la pila de la invocación actual desort_bytes
. Cuando se llama, salta alcompar
código y pasa esa dirección.Este desorden no es necesario en arquitecturas como PowerPC, donde la ABI especifica que un puntero de función es en realidad un "puntero gordo", una estructura que contiene tanto un puntero al código ejecutable como otro puntero a los datos. Sin embargo, en x86, un puntero de función es solo un puntero.
fuente
Para C, un trampolín sería un puntero de función:
Editar: El compilador generaría implícitamente trampolines más esotéricos. Uno de esos usos sería una mesa de salto. (Aunque claramente hay otros más complicados cuanto más abajo empiece a intentar generar código complicado).
fuente
Ahora que C # tiene funciones locales , el kata de codificación del juego de bolos se puede resolver elegantemente con un trampolín:
El método
Game.RollMany
se llama con una serie de rollos: normalmente 20 rollos si no hay repuestos o golpes.La primera línea inmediatamente llama a la función de trampolín:
return Trampoline(1, 0, rs.ToList());
. Esta función local atraviesa de forma recursiva la matriz rolls. La función local (el trampolín) permite que el recorrido comience con dos valores adicionales: comenzar conframe
1 y elrsf
(resultado hasta ahora) 0.Dentro de la función local existe un operador ternario que maneja cinco casos:
La continuación del recorrido se realiza volviendo a llamar al trampolín, pero ahora con valores actualizados.
Para obtener más información, busque: " acumulador de recursividad de cola ". Tenga en cuenta que el compilador no optimiza la recursividad de cola. Por muy elegante que sea esta solución, es probable que no sea el ayuno.
fuente
fuente