La définition d'un combinateur Y en F # est
let rec y f x = f (y f) x
f s'attend à avoir comme premier argument une continuation pour les sous-problèmes récursifs. En utilisant le yf comme suite, nous voyons que f sera appliqué aux appels successifs au fur et à mesure que nous développerons
let y f x = f (y f) x = f (f (y f)) x = f (f (f (y f))) x etc...
Le problème est que, a priori, ce schéma empêche d'utiliser toute optimisation d'appel de queue: en effet, il pourrait y avoir une opération en attente dans les f, auquel cas nous ne pouvons pas simplement muter la trame de pile locale associée à f.
Donc :
- d'une part, l'utilisation du combinateur Y nécessite une continuation explicitement différente de la fonction elle-même.
- sur l'othe pour appliquer le TCO, nous aimerions n'avoir aucune opération en attente dans f et n'appeler que f lui-même.
Connaissez-vous un moyen de réconcilier ces deux-là? Comme un Y avec astuce accumulateur, ou un Y avec astuce CPS? Ou un argument prouvant qu'il n'y a aucun moyen de le faire?
f
. Nous pouvons voir que cela y
pourrait appeler f
avec un thunk (y f)
, mais comme vous le dites, il f
pourrait y avoir une opération en attente. Je pense qu'il serait intéressant de savoir s'il existe un combinateur séparé qui est plus convivial pour les appels de queue. Je me demande si cette question obtiendrait une meilleure attention sur le site CS Stackexchange?