Prima di tutto, F # supporta le funzioni mutuamente ricorsive in modo nativo, perché può beneficiare dall'istruzione tailcall
disponibile in .NET IL (MSDN). Tuttavia, questo è un po 'complicato e potrebbe non funzionare su alcune implementazioni alternative di .NET (ad esempio Compact Framework), quindi a volte potrebbe essere necessario gestirli manualmente.
In generale, che ci sono un paio di modi per trattare con esso:
Trampolino - un'eccezione quando la profondità di ricorsione è troppo alto e mettere in atto un ciclo di livello superiore che maniglie l'eccezione (l'eccezione porterebbe informazioni per riprendere la chiamata). Invece di eccezioni, puoi anche semplicemente restituire un valore che specifica che la funzione dovrebbe essere richiamata di nuovo.
Rilassatevi con timer - quando la profondità di ricorsione è troppo alto, si crea un timer e dargli un callback che verrà chiamata dal timer dopo un certo tempo molto breve (il timer continuerà la ricorsione, ma il lo stack usato verrà eliminato).
La stessa cosa potrebbe essere eseguita utilizzando uno stack globale che memorizza il lavoro che deve essere eseguito. Invece di programmare un timer, si aggiungerà la funzione allo stack. Al livello più alto, il programma sceglieva le funzioni dallo stack e le eseguiva.
Per dare un esempio specifico della prima tecnica, in F # si potrebbe scrivere questo:
type Result<´T> =
| Done of ´T
| Call of (unit -> ´T)
let rec factorial acc n =
if n = 0 then Done acc
else Call(fun() -> factorial (acc * n) (n + 1))
questo può essere utilizzato per le funzioni ricorsive reciprocamente pure. Il ciclo imperativo chiamerebbe semplicemente la funzione f
memorizzata in Call(f)
finché non produce Done
con il risultato finale. Penso che questo sia probabilmente il modo più pulito per implementarlo.
Sono sicuro che ci sono altre tecniche sofisticate per affrontare questo problema, ma quelle sono le due che conosco (e che ho usato).
fonte
2010-05-09 19:21:46
Quella cosa timer è qualcosa di nuovo per me) grazie – Bubba88