Programmazione asincrona in linguaggi funzionali

29

Sono principalmente un programmatore C / C ++, il che significa che la maggior parte della mia esperienza è con paradigmi procedurali e orientati agli oggetti. Tuttavia, come molti programmatori C ++ sono consapevoli, C ++ ha spostato l'accento nel corso degli anni verso uno stile funzionale, culminando infine nell'aggiunta di lambda e chiusure in C ++ 0x.

Indipendentemente da ciò, mentre ho una notevole esperienza nella codifica in uno stile funzionale con C ++, ho pochissima esperienza con linguaggi funzionali reali come Lisp, Haskell, ecc.

Recentemente ho iniziato a studiare questi linguaggi, perché l'idea di "nessun effetto collaterale" in linguaggi puramente funzionali mi ha sempre intrigato, specialmente per quanto riguarda le sue applicazioni alla concorrenza e al calcolo distribuito.

Tuttavia, provenendo da uno sfondo C ++, sono confuso su come questa philsophy "senza effetti collaterali" funzioni con la programmazione asincrona. Per programmazione asincrona si intende qualsiasi stile framework / API / coding che invii i gestori di eventi forniti dall'utente per gestire eventi che si verificano in modo asincrono (al di fuori del flusso del programma). Ciò include librerie asincrone come Boost.ASIO, o anche semplicemente vecchio C gestori di segnale o gestori di eventi GUI Java.

L'unica cosa che tutti hanno in comune è che la natura della programmazione asincrona sembra richiedere la creazione di effetti collaterali (stato), in modo che il flusso principale del programma diventi consapevole del fatto che è stato richiamato un gestore di eventi asincrono. Tipicamente, in un framework come Boost.ASIO, un gestore di eventi modifica lo stato di un oggetto, in modo che l'effetto dell'evento venga propagato oltre la durata della funzione del gestore di eventi. In realtà, che altro può fare un gestore di eventi? Non può "restituire" un valore al punto di chiamata, poiché non vi è alcun punto di chiamata. Il gestore di eventi non fa parte del flusso principale del programma, quindi l'unico modo in cui può avere un effetto sul programma effettivo è quello di modificare alcuni stati (oppure longjmp in un altro punto di esecuzione).

Quindi sembra che la programmazione asincrona riguardi in modo asincrono la produzione di effetti collaterali. Questo sembra completamente in disaccordo con gli obiettivi della programmazione funzionale. In che modo questi due paradigmi sono riconciliati (in pratica) in linguaggi funzionali?

    
posta Charles Salvia 22.01.2011 - 02:26
fonte

5 risposte

10

Tutta la tua logica è valida, tranne che penso che la tua comprensione della programmazione funzionale sia un po 'troppo estrema. Nella programmazione funzionale del mondo reale, proprio come la programmazione orientata agli oggetti o imperativa riguarda mindset e come ci si avvicina al problema. Puoi ancora scrivere programmi nello spirito della programmazione funzionale mentre modifichi lo stato dell'applicazione.

In effetti, devi modificare lo stato dell'applicazione per fare effettivamente do . I ragazzi di Haskell ti diranno che i loro programmi sono "puri" perché avvolgono tutti i loro cambiamenti di stato in una monade. Tuttavia, i loro programmi interagiscono ancora con il mondo esterno. (Altrimenti qual è il punto!)

L'enfasi sulla programmazione funzionale "senza effetti collaterali" quando ha senso. Tuttavia, per programmare in tempo reale, come hai detto tu, devi modificare lo stato del mondo. (Ad esempio, rispondere agli eventi, scrivere su disco e così via.)

Per ulteriori informazioni sulla programmazione asincrona nei linguaggi funzionali, ti invito vivamente a consultare i flussi di lavoro asincroni di F # modello di programmazione. Ti permette di scrivere programmi funzionali nascondendo tutti i dettagli disordinati della transizione dei thread all'interno di una libreria. (In un modo molto simile alle monadi di stile Haskell.)

Se il "corpo" del thread calcola semplicemente un valore, quindi generare più thread e averli calcolare i valori in parallelo è ancora all'interno del paradigma funzionale.

    
risposta data 22.01.2011 - 02:54
fonte
7

Questa è una domanda affascinante. L'interpretazione più interessante è, a mio avviso, l'approccio adottato in Clojure e spiegato in questo video:

link

Fondamentalmente la "soluzione" proposta è la seguente:

  • Scrivi la maggior parte del tuo codice come funzioni "pure" classiche con strutture di dati immutabili e senza effetti collaterali
  • Gli effetti collaterali sono isolati tramite l'uso di riferimenti gestiti che controllano le modifiche soggette alle regole della memoria transazionale del software (cioè tutti gli aggiornamenti allo stato mutabile avvengono all'interno di una transazione isolata corretta)
  • Se osservi questa visione del mondo, puoi vedere "eventi" asincroni come trigger per un aggiornamento transazionale dello stato mutabile in cui l'aggiornamento è di per sé una funzione pura.

Probabilmente non ho espresso l'idea chiaramente come altri hanno fatto, ma spero che questo dia l'idea generale - fondamentalmente sta usando un sistema STM concorrente per fornire il "ponte" tra pura programmazione funzionale e gestione asincrona degli eventi.

    
risposta data 13.08.2011 - 00:07
fonte
5

Una nota: un linguaggio funzionale è puro, ma il suo runtime non lo è.

Ad esempio, i runtime di Haskell comportano code, multiplexing dei thread, garbage collection, ecc. Tutto ciò non è puro.

Un buon esempio è la pigrizia. Haskell supporta la valutazione lazy (che è il default, in realtà). Si crea un valore pigro preparando un'operazione, è possibile quindi creare più copie di questo valore ed è ancora "pigro" purché non sia necessario. Quando il risultato è necessario, o se il runtime trova un po 'di tempo, il valore viene effettivamente calcolato e lo stato dell'oggetto pigro cambia per riflettere che non è più necessario eseguire il calcolo (ancora una volta) per ottenere il risultato. È ora disponibile attraverso tutti i riferimenti, quindi lo stato dell'oggetto è cambiato, anche se è un linguaggio puro.

    
risposta data 22.01.2011 - 12:55
fonte
2

I'm confused as to how this "no side-effects" philsophy works with asynchronous programming. By asynchronous programming I mean ...

Questo sarebbe il punto, quindi.

Un suono, nessun effetto collaterale è incompatibile con i framework che dipendono dallo stato. Trova un nuovo framework.

Lo standard WSGI di Python, ad esempio, ci consente di creare applicazioni con effetti collaterali.

L'idea è che i vari "cambiamenti di stato" siano riflessi da un ambiente di valori che può essere costruito in modo incrementale. Ogni richiesta è una pipeline di trasformazioni.

    
risposta data 22.01.2011 - 02:59
fonte
1

Avendo imparato l'incapsulamento da Borland C ++ dopo aver imparato C, quando Borland C ++ mancava di template che abilitassero i generici, il paradigma di orientamento agli oggetti mi metteva a disagio. Un modo un po 'più naturale di calcolare sembrava filtrare i dati attraverso i tubi. Il flusso verso l'esterno aveva un'identità separata e indipendente dal flusso di input immutabile verso l'interno, piuttosto che essere considerato come un effetto collaterale, cioè ogni fonte di dati (o filtro) era autonoma dagli altri. La pressione del tasto (un evento di esempio) vincolava le combinazioni di input degli utenti asincroni ai keycode disponibili. Le funzioni operano sugli argomenti dei parametri di input e lo stato incapsulato dalla classe è solo una scorciatoia per evitare di passare esplicitamente argomenti ripetitivi tra piccoli sottoinsiemi di funzioni, oltre ad essere precisi del contesto associato che impedisce di abusare di tali argomenti da qualsiasi funzione arbitraria.

Aderire rigidamente a un paradigma particolare causa l'inconveniente di occuparsi di astrazioni che perdono, per es. i runtime commerciali come JRE, DirectX, .net sono i proponenti orientati agli oggetti di destinazione. Per limitare l'inconveniente, le lingue optano per monade sofisticate dal punto di vista accademico come Haskell o supporto flessibile multi-paradigma come F # alla fine ottenuto. A meno che l'incapsulamento non sia utile in alcuni casi di utilizzo dell'ereditarietà multipla, l'approccio multi-paradigma potrebbe essere un'alternativa superiore ad alcuni, a volte complessi, schemi di programmazione specifici del paradigma.

    
risposta data 22.11.2014 - 20:13
fonte

Leggi altre domande sui tag