Estou trabalhando em minha própria pequena linguagem de programação para fins educacionais e me deparei com um pouco de problema. Existem algumas soluções diferentes para isso, mas todas elas parecem deselegantes - e pelo que entendi, desnecessárias. Mas, lendo os livros que tenho e as pesquisas no Google, não consigo encontrar a solução elegante.
Portanto, o problema é que estou construindo o cálculo lambda básico como o entendo. Eu defini verdadeiro / falso como termos de abstração. Eu posso combiná-los com funções para fazer se / então / outro tipo de comportamento. O problema vem com loops. Eu posso definir um loop while básico via recursão, mas na prática, isso causa um estouro de pilha. Pelo que entendi, a solução usual seria executar a otimização de chamada de cauda, mas não vejo como posso - os condicionais são definidos no idioma. Por isso, o compilador não sabe que o corpo do loop while está na posição de cauda.
O livro do dragão se concentra na implementação do loop, assumindo que há rótulos e gotos. Eu certamente poderia fazer isso. Parece que outras linguagens que não constroem em looping constroem pelo menos em condicionais e depois fazem o TCO. E eu certamente poderia fazer isso também. Mas meu entendimento é que, enquanto eu puder aplicar abstrações e executar reduções, os loops (e tudo o mais) deverão poder ser construídos a partir desses blocos básicos.
Então o que estou perdendo? Ou esse é um daqueles casos em que "você pode modelar qualquer coisa depois de ter X e Y" não é o mesmo que "você pode modelar qualquer coisa depois de ter X e Y em um computador real" e os internos são necessários para fins?