qual è lo scopo delle frecce?

62

Sto imparando la programmazione funzionale con Haskell e cerco di afferrare i concetti capendo prima perché ne ho bisogno.

Mi piacerebbe conoscere l'obiettivo delle frecce nei linguaggi di programmazione funzionale. Che problema risolvono? Ho controllato link e link . Tutto quello che capisco è che sono usati per descrivere i grafici per i calcoli, e che consentono una codifica più semplice di stile senza punti.

L'articolo assume che lo stile point free è generalmente più facile da capire e da scrivere. Questo mi sembra abbastanza soggettivo. In un altro articolo ( link ), viene implementato un gioco dell'impiccato, ma non riesco a vedere come le frecce facciano questa implementazione naturale.

Potrei trovare molti documenti che descrivono il concetto, ma nulla sulla motivazione.

Cosa mi manca?

    
posta Simon 17.10.2011 - 13:40
fonte

4 risposte

41

Mi rendo conto che sto arrivando in ritardo alla festa, ma qui hai avuto due risposte teoriche e volevo fornire un'alternativa pratica per masticare. Sto arrivando a questo come a un Haskell noob parente che è stato recentemente sfidato a forza attraverso l'argomento di Arrows per un progetto al quale sto lavorando attualmente.

In primo luogo, puoi risolvere in modo produttivo la maggior parte dei problemi in Haskell senza raggiungere Arrows. Alcuni Haskellers notabili non li gradiscono e non li usano (vedi qui , qui e qui per ulteriori informazioni su questo). Quindi se stai dicendo a te stesso "Ehi, non ho bisogno di questi", capisci che potresti essere sinceramente corretto.

Quello che ho trovato più frustrante di Arrows quando li ho imparati per la prima volta è stato il modo in cui i tutorial sull'argomento hanno inevitabilmente raggiunto l'analogia dei circuiti. Se si guarda il codice Arrow - la varietà zuccherata, almeno - non assomiglia a nulla come un Hardware Defnition Language. I tuoi ingressi si allineano sulla destra, i tuoi output sulla sinistra e se non riesci a collegarli correttamente, semplicemente non riescono a sparare. Mi sono detto: Davvero? È qui che siamo finiti? Abbiamo creato un linguaggio così completamente di alto livello che ancora una volta è costituito da fili di rame e saldatura?

La risposta corretta a questo, per quanto sono stato in grado di determinare, è: In realtà, sì. Il caso d'uso dell'assassino in questo momento per Arrows è FRP (pensa a Yampa, giochi, musica e sistemi reattivi in generale). Il problema che affligge FRP è in gran parte lo stesso problema che affligge tutti gli altri sistemi di messaggistica sincrona: come cablare un flusso continuo di input in un flusso continuo di uscite senza perdere informazioni rilevanti o perdite elastiche. È possibile modellare gli stream come elenchi: diversi sistemi FRP recenti utilizzano questo approccio, ma quando si dispone di molti input gli elenchi diventano quasi impossibili da gestire. Hai bisogno di isolarti dalla corrente.

Ciò che le frecce consentono nei sistemi FRP è la composizione di funzioni in una rete, mentre allo stesso tempo estrae completamente qualsiasi riferimento ai valori sottostanti che vengono passati da quelle funzioni. Se sei nuovo a FP, all'inizio questo può essere fonte di confusione, e poi strabiliante quando ne hai assorbito le implicazioni. Recentemente hai assorbito l'idea che le funzioni possono essere astratte e come capire un elenco come [(*), (+), (-)] come di tipo [(a -> a -> a)] . Con le frecce, puoi spingere l'astrazione di un livello ulteriormente.

Questa ulteriore capacità di astrazione porta con sé i suoi pericoli. Per prima cosa, può spingere GHC in casi d'angolo in cui non sa cosa fare delle supposizioni di tipo. Dovrai essere preparato a pensare a livello di tipo: questa è un'eccellente opportunità per conoscere tipi e RankNTypes e altri argomenti simili.

Ci sono anche una serie di esempi di ciò che chiamerei "Stupid Arrow Stunts" in cui il programmatore raggiunge un combinatore di frecce solo perché vuole mostrare un trucco pulito con le tuple. (Ecco il mio contributo banale alla follia .) Sentiti libero ignorare tali hot-dogging quando lo si incontra in natura.

NOTA: Come ho detto sopra, sono un noob relativo. Se ho promulgato qualche malinteso sopra, sentiti libero di correggermi.

    
risposta data 09.11.2011 - 23:48
fonte
28

Questa è una specie di risposta "soft", e non sono sicuro che qualsiasi riferimento in realtà lo dichiari in questo modo, ma questo è il modo in cui sono arrivato a pensare alle frecce:

Un tipo di freccia A b c è fondamentalmente una funzione b -> c ma con più struttura nello stesso modo in cui un valore monadico M a ha più struttura di un semplice vecchio a .

Ora, ciò che accade in questa struttura extra dipende dalla particolare istanza della freccia di cui stai parlando. Proprio come con monads IO a e Maybe a hanno ciascuna una struttura aggiuntiva diversa.

La cosa che ottieni con le Monade è l'impossibilità di passare da M a a a . Ora questo può sembrare un limite, ma in realtà è una caratteristica: il sistema di tipi ti protegge dal trasformare un valore monadico in un semplice vecchio valore. Puoi utilizzare il valore solo partecipando alla monade tramite >>= o alle operazioni primitive della particolare istanza monad.

Allo stesso modo la cosa che ottieni da A b c è un'incapacità di costruire una nuova "funzione" che consuma c che consuma. La freccia ti protegge dal consumo di b e dalla creazione di un c eccetto che partecipando ai vari combinatori di frecce o utilizzando le operazioni primitive della particolare istanza di freccia.

Ad esempio le funzioni di segnale in Yampa sono all'incirca (Time -> a) -> (Time -> b) , ma in aggiunta devono obbedire a una certa limitazione causalità : l'uscita al tempo t è determinata dai valori passati dell'input segnale: non puoi guardare nel futuro. Quindi quello che fanno è invece di programmare con (Time -> a) -> (Time -> b) , si programma con SF a b e si costruiscono le funzioni di segnale da primitive. Succede che dal momento che SF a b si comporta molto come una funzione, in modo che la struttura comune sia quella che viene chiamata una "freccia".

    
risposta data 17.10.2011 - 23:17
fonte
14

Mi piace pensare a Arrows, come Monads e Functors, in quanto consente al programmatore di eseguire composizioni esotiche di funzioni.

Senza Monade o Frecce (e Funzionalità), la composizione delle funzioni in un linguaggio funzionale è limitata all'applicazione di una funzione al risultato di un'altra funzione. Con monadi e funtori, è possibile definire due funzioni e quindi scrivere un codice riutilizzabile separato che specifica in che modo tali funzioni, nel contesto della particolare monade, interagiscono tra loro e con i dati che vengono passati in esse. Questo codice è inserito nel codice di bind della Monade. Quindi una monade è una vista, solo un contenitore per codice di bind riutilizzabile. Le funzioni si compongono diversamente nel contesto di una monade da un'altra monade.

Un semplice esempio è la Forse monade, dove c'è un codice nella funzione bind tale che se una funzione A è composta con una funzione B all'interno di una Forse monade, e B produce un Nulla, allora il codice di bind assicurerà che il la composizione delle due funzioni emette un Nothing, senza preoccuparsi di applicare A al valore Nothing che esce da B. Se non ci fosse la monade, il programmatore dovrebbe scrivere il codice in A per verificare un input Nothing.

Monade significa anche che il programmatore non ha bisogno di digitare esplicitamente i parametri che ogni funzione richiede nel codice sorgente - la funzione bind gestisce il passaggio dei parametri. Quindi, usando le monadi, il codice sorgente può iniziare a somigliare più a una catena statica di nomi di funzioni, piuttosto che a una funzione A "chiama" la funzione B con i parametri C e D - il codice inizia a somigliare più a un circuito elettronico che a macchina in movimento - più funzionale che imperativo.

Le frecce collegano anche funzioni insieme a una funzione di bind, fornendo funzionalità riutilizzabili e nascondendo i parametri. Ma le frecce possono essere collegate e composte insieme e possono facoltativamente indirizzare i dati ad altre frecce in fase di runtime. Ora puoi applicare i dati a due percorsi di frecce, che "fanno cose diverse" ai dati e riassemblare il risultato. Oppure puoi selezionare il ramo di Frecce a cui passare i dati, in base a qualche valore nei dati. Il codice risultante è ancora più simile a un circuito elettronico, con interruttori, ritardi, integrazione, ecc. Il programma sembra molto statico e non si dovrebbe essere in grado di vedere molta manipolazione dei dati in corso. Ci sono sempre meno parametri a cui pensare e meno bisogno di pensare a quali valori possono o non possono prendere i parametri.

La scrittura di un programma Arrowized consiste principalmente nella selezione di scaffali Frecce come splitter, interruttori, delay e integratori, funzioni di sollevamento in quelle Frecce e collegamento delle Frecce insieme per formare frecce più grandi. In Arrowized Functional Reactive Programming, le frecce formano un loop, con input dal mondo che viene combinato con l'output dell'ultima iterazione del programma, in modo che l'output reagisca all'input del mondo reale.

Uno dei valori del mondo reale è il tempo. In Yampa, la freccia della funzione segnale filtra invisibilmente il parametro temporale attraverso il programma del computer - non si accede mai al valore temporale, ma se si connette una freccia integratore nel programma, esso produrrà valori integrati nel tempo che è possibile utilizzare per passare a altre frecce.

    
risposta data 09.10.2012 - 13:28
fonte
3

Solo un'aggiunta alle altre risposte: Personalmente mi aiuta molto a capire che cos'è un tale concetto (matematicamente) e in che modo si riferisce ad altri concetti che conosco.

Nel caso delle frecce, ho trovato utile il seguente documento: confronta monadi, funtori applicativi (espressioni idiomatiche) e frecce: Idiomi sono ignari, le frecce sono meticolose, le monadi sono promiscue di Sam Lindley, Philip Wadler e Jeremy Yallop.

Inoltre, credo che nessuno abbia menzionato questo link che potrebbe fornire idee e letteratura sull'argomento.

    
risposta data 09.10.2012 - 20:32
fonte

Leggi altre domande sui tag