La chiamata / cc di Scheme può implementare tutte le strutture di flusso di controllo conosciute?


13

La pagina "Advanced Scheme: Some Naughty Bits" indica:

Le continuazioni sono un potente costrutto del flusso di controllo dal quale è possibile derivare quasi ogni altra struttura [...] del flusso di controllo.

Ho pensato che Scheme call/cc, essendo correlato (*) all'operatore J di Peter Landin, potesse essere usato per implementare qualsiasi struttura di flusso di controllo conosciuta?

Con la "struttura del flusso di controllo" sto pensando in particolare alla loro descrizione di Wikipedia , ad esempio eccezioni, coroutine, fili verdi e così via.

In particolare, ci sono esempi di strutture di flusso di controllo che non possono essere implementate usando call/cc?

(*) Non sono stato in grado di scavare alcun documento che dimostri che call/ccè potente come l'operatore J. Un articolo di Felleisen (che non ho letto e che certamente ho problemi a comprenderlo appieno) lo analizza e sembra concludere che, sebbene si trovino in classi di complessità diverse, sono formalmente equivalenti.

(Nota anche che ho aggiornato la domanda in base ai commenti qui sotto)

Aggiornare

Sulla base dell'eccellente risposta di @Neel di seguito, ho esaminato i siti che commentano continuazioni delimitate e non delimitate , e in effetti sembra che call/cc, pur non essendo delimitate, non sia sufficiente. Nel frattempo, sembra che si possano usare continuazioni delimitate di prima classe (come shift/reset) per esprimere qualsiasi struttura del flusso di controllo.


5
Qual è la definizione formale di "struttura del flusso di controllo"?
Huck Bennett,

4
Ri: continuazioni non delimitate. Hai letto il documento di riferimento di Hayo Thielecke? L'affermazione effettiva è che le continuazioni non delimitate fornite dacall/cc non possono esprimere eccezioni in assenza di stato . (Come sottolinea Thielecke, le eccezioni possono essere implementate passando due continuazioni, una per il programma e l'altra per il gestore delle eccezioni, ma ciò richiede più di un semplice call/cc.)
rici

@Rici: ho sfogliato solo le prime pagine. (La lettura dei documenti mi richiede molto tempo). Grazie per il commento!
CSL

@HuckBennett Non ho una definizione formale, ma informalmente intendo quello che ha descritto su en.wikipedia.org/wiki/Control_flow , in particolare intendo che puoi usare continuazioni per esprimere e, soprattutto, per implementare, coroutine, thread verdi, eccezioni, istruzioni di ambescape, operatore e così via.
csl

2
@csl Oltre a rendere più preciso il significato di "struttura del flusso di controllo", è necessario anche chiarire cosa significa "esprimere" qualcosa. Questo è un problema difficile e la risposta alla tua domanda dipende fortemente da ciò che conti come espressione. Dopotutto, puoi sempre codificare in qualche modo una macchina Turing che codifica un interprete di una lingua con eccezioni (ad esempio Java). Ma probabilmente non è quello che hai in mente, quindi devi porre forti vincoli al concetto di "espressione" (ad es. Composizionalità e / o completa astrazione).
Martin Berger,

Risposte:


11

In questa risposta, prenderò "espressibile" per significare "macro-espressibile" nel senso di Felleisen 1991, Il potere espressivo dei linguaggi di programmazione . (Intuitivamente, una funzione del linguaggio è macro-espressibile se è possibile definirla come una trasformazione di origine locale, senza utilizzare una trasformazione dell'intero programma.)

Con questa definizione, la risposta è no : il controllo delimitato non è macro-esprimibile nel lambda-calculus + call / cc. Per esprimere operatori di controllo delimitati usando call / cc. Per implementare i delimitatori di controllo (la parte di reset di shift / reset), è necessario un certo stato per simulare i segni di continuazione, essenzialmente per codificare uno stack per simulare la durata dinamica dei segni di continuazione.

Tuttavia, il controllo delimitato è un effetto universale, nel senso seguente. Nella sua tesi di dottorato , Andrzej Filinski ha mostrato che qualsiasi effetto collaterale esprimibile è codificabile usando continuazioni delimitate, o call / cc e una singola cella di stato. In parole povere, un "effetto collaterale espressibile" è qualsiasi effetto il cui tipo monadico può essere definito in termini di tipi del linguaggio di programmazione.

Sorprendentemente, questa idea sembra abbastanza interessante in pratica. Nell'ultimo decennio, Gordon Plotkin e John Power hanno sostenuto l'idea di prendere una semantica algebrica delle teorie degli effetti : l'idea è quella di specificare le operazioni di effetto collaterale che ti interessano e le equazioni che ti aspetti che soddisfino, e poi puoi ottenere genericamente una semantica prendendo la monade libera su questa teoria.

Matija Pretnar e Andrej Bauer hanno adottato questo approccio matematico, quindi lo hanno implementato nel loro linguaggio Eff per inventare un nuovo linguaggio costrutto soprannominato "gestori di effetti": è possibile scrivere codice che utilizza un insieme di caratteristiche imperative e quindi fornire una semantica alle caratteristiche imperative scrivendo una serie di gestori che dicono come implementare ogni operazione efficace.


Ma se la definizione è: "Puoi implementare qualsiasi struttura di flusso di controllo usando Scheme e call / cc" (senza emulazione), allora la risposta deve essere ? Guardando la discussione LtU lambda-the-ultimate.org/node/966 sembra che Oleg Kiselyouv abbia implementato tutti e quattro gli operatori F nello schema con call / cc: okmij.org/ftp/continuations/… - excerpt "Il codice si basa su chiamata / cc per l'acquisizione di continuazioni non delimitate e utilizza una cella mutabile globale. Si scopre che ciò è sufficiente per implementare [...] gli altri operatori F ". ... "-F- attraverso + F + F".
CSL

Riconosco il tuo uso della "macro-espressibilità" di Felleisen come cornice per la tua risposta, ma come puoi vedere ho già cambiato la mia domanda per significare specificamente "implementare [nello schema] usando call / cc". E mentre Oleg Kiselyov ha bisogno di introdurre una cellula mutabile globale per implementare tutti e quattro gli operatori F per continuazioni delimitate, non penso che ciò equivale a una "grande ristrutturazione globale del programma" --- in pratica, ovviamente.
CSL

Accetterò questa risposta. Vorrei anche fare riferimento al testo su okmij.org/ftp/continuations/undelimited.html#delim-vs-undelim che ha ulteriori indicazioni. Sembra inoltre che continuazioni delimitate di prima classe come shift / reset possano essere utilizzate per implementare qualsiasi struttura di flusso di controllo. Dal link: "Le continuazioni delimitate di prima classe possono esprimere qualsiasi effetto computazionale esprimibile, comprese le eccezioni e lo stato mutabile".
CSL
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.