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.