Durante discussões recentes no trabalho, alguém se referiu a uma função de trampolim.
Eu li a descrição na Wikipedia . É o suficiente para dar uma ideia geral da funcionalidade, mas gostaria de algo um pouco mais concreto.
Você tem um trecho de código simples que ilustraria um trampolim?
Respostas:
Há também o sentido LISP de 'trampolim', conforme descrito na Wikipedia:
Digamos que estejamos usando Javascript e queremos escrever a função Fibonacci ingênua no estilo continuation-pass. A razão pela qual faríamos isso não é relevante - para portar Scheme para JS, por exemplo, ou para brincar com CPS que temos que usar de qualquer maneira para chamar funções do lado do servidor.
Então, a primeira tentativa é
Mas, ao executá-lo
n = 25
no Firefox, aparecerá um erro 'Muita recursão!'. Bem, este é exatamente o problema (falta de otimização de chamada de cauda em Javascript) que o trampolim resolve. Em vez de fazer uma chamada (recursiva) para uma função, vamosreturn
usar uma instrução (thunk) para chamar essa função, para ser interpretada em um loop.fonte
Deixe-me adicionar alguns exemplos de função fatorial implementada com trampolins, em diferentes linguagens:
Scala:
Java:
C (azar sem implementação de grandes números):
fonte
if (n < 2) Done(product)
, SO não me permitiu editar 1 símbolo ...Vou dar um exemplo que usei em um patch anti-cheat para um jogo online.
Eu precisava ser capaz de verificar todos os arquivos carregados pelo jogo para modificação. Portanto, a maneira mais robusta que descobri de fazer isso foi usar um trampolim para CreateFileA. Então, quando o jogo fosse lançado, eu encontraria o endereço de CreateFileA usando GetProcAddress, então eu modificaria os primeiros bytes da função e inseriria o código de montagem que iria pular para minha própria função de "trampolim", onde eu faria algumas coisas, e então, eu voltaria para o próximo local em CreateFile após meu código jmp. Ser capaz de fazer isso de forma confiável é um pouco mais complicado do que isso, mas o conceito básico é apenas conectar uma função, forçá-la a redirecionar para outra função e, em seguida, voltar para a função original.
Edit: A Microsoft tem uma estrutura para esse tipo de coisa que você pode ver. Desvios chamados
fonte
No momento, estou experimentando maneiras de implementar a otimização de chamada de cauda para um intérprete do Scheme e, no momento, estou tentando descobrir se o trampolim seria viável para mim.
Pelo que entendi, é basicamente apenas uma série de chamadas de função realizadas por uma função de trampolim. Cada função é chamada de conversão e retorna a próxima etapa no cálculo até que o programa termine (continuação vazia).
Aqui está o primeiro código que escrevi para melhorar minha compreensão do trampolim:
resulta em:
fonte
Aqui está um exemplo de funções aninhadas:
compar
não pode ser uma função externa, pois usanbytes
, que só existe durante asort_bytes
chamada. Em algumas arquiteturas, uma pequena função de stub - o trampolim - é gerada em tempo de execução e contém a localização da pilha da chamada atual desort_bytes
. Quando chamado, ele salta para ocompar
código, passando esse endereço.Essa bagunça não é necessária em arquiteturas como PowerPC, onde a ABI especifica que um ponteiro de função é na verdade um "ponteiro gordo", uma estrutura que contém um ponteiro para o código executável e outro ponteiro para dados. No entanto, no x86, um ponteiro de função é apenas um ponteiro.
fonte
Para C, um trampolim seria um ponteiro de função:
Edit: Trampolins mais esotéricos seriam gerados implicitamente pelo compilador. Um desses usos seria uma mesa de salto. (Embora haja claramente mais complicados quanto mais adiante você começa a tentar gerar um código complicado.)
fonte
Agora que C # tem funções locais , o kata de codificação do jogo de boliche pode ser resolvido elegantemente com um trampolim:
O método
Game.RollMany
é chamado com uma série de lançamentos: normalmente 20 lançamentos se não houver sobressalentes ou golpes.A primeira linha imediatamente chama a função de trampolim:
return Trampoline(1, 0, rs.ToList());
. Esta função local percorre recursivamente a matriz de rolos. A função local (o trampolim) permite que a travessia comece com dois valores adicionais: comece comframe
1 e orsf
(resultado até agora) 0.Dentro da função local existe um operador ternário que lida com cinco casos:
A continuação da travessia é feita chamando o trampolim novamente, mas agora com os valores atualizados.
Para obter mais informações, pesquise: " acumulador de recursão de cauda ". Lembre-se de que o compilador não otimiza a recursão final. Portanto, por mais elegante que seja essa solução, provavelmente não será o jejum.
fonte
fonte