Non mi interessa la prima definizione - quelle non mi aiuterebbero a scrivere un vero programma (+1 se mi convinci che ho torto). Per favore aiutami a capire la seconda definizione. Penso che mappa, filtro e riduzione siano utili: mi consentono di programmare a un livello superiore: meno errori, codice più breve e più chiaro.
Le due definizioni sono fondamentalmente la stessa cosa. Il primo si basa sulla definizione formale e gli esempi che fornisci sono combinatori primitivi: i più piccoli elementi costitutivi possibili. Possono aiutarti a scrivere un programma reale nella misura in cui, con loro, puoi costruire combinatori più sofisticati. Pensa a combinatori come S e K come il linguaggio macchina di un ipotetico "computer combinatorio". I computer reali non funzionano in questo modo, ovviamente, quindi in pratica di solito avrai operazioni di livello superiore implementate dietro le quinte in altri modi, ma la base concettuale è ancora uno strumento utile per comprendere il significato di quelle di livello superiore operazioni.
La seconda definizione che fornisci è più informale e riguarda l'uso di combinatori più sofisticati, sotto forma di funzioni di ordine superiore che combinano altre funzioni in vari modi. Nota che se gli elementi costitutivi di base sono i combinatori primitivi sopra, tutto ciò che viene costruito da essi è una funzione di ordine superiore e anche un combinatore. In un linguaggio in cui esistono altre primitive, tuttavia, hai una distinzione tra cose che sono o non sono funzioni, nel qual caso un combinatore è tipicamente definito come una funzione che manipola altre funzioni in modo generale, piuttosto che operare su qualsiasi non- funzionare direttamente le cose.
Quali sono altri esempi di combinatori come map, filter?
Troppi da elencare! Entrambi trasformano una funzione che descrive il comportamento su un singolo valore in una funzione che descrive il comportamento su un'intera raccolta. Puoi anche avere funzioni che trasformano solo altre funzioni, come comporle end-to-end o suddividere e ricombinare argomenti. È possibile disporre di combinatori che trasformano operazioni a passaggio singolo in operazioni ricorsive che producono o consumano raccolte. O tutti i tipi di altre cose, davvero.
Quali combinatori implementano spesso i linguaggi di programmazione?
Questo cambierà parecchio. Esistono relativamente pochi combinatori completamente generici, per lo più quelli primitivi menzionati sopra, quindi nella maggior parte dei casi i combinatori avranno una certa consapevolezza di qualsiasi struttura di dati utilizzata (anche se tali strutture di dati sono costruite comunque da altri combinatori), in cui caso ci sono tipicamente una manciata di combinatori "completamente generici" e poi qualunque forma specializzata che qualcuno ha deciso di fornire. Ci sono un numero ridicolo di casi in cui (versioni adeguatamente generalizzate di) map, fold e unfold sono sufficienti per fare quasi tutto ciò che potresti desiderare.
In che modo i combinatori possono aiutarmi a progettare un'API migliore?
Esattamente come hai detto, pensando in termini di operazioni di alto livello e il modo in cui queste interagiscono, invece che di dettagli di basso livello.
Pensa alla popolarità dei cicli in stile "per ogni" sulle raccolte, che ti consentono di astrarre sui dettagli dell'enumerazione di una collezione. Queste sono solo operazioni di mappatura / piegatura nella maggior parte dei casi, e rendendolo un combinatore (piuttosto che una sintassi incorporata) puoi fare cose come prendere due loop esistenti e combinarli direttamente in più modi - annidarli uno dentro l'altro, fatene uno dopo l'altro, e così via, semplicemente applicando un combinatore, invece di destreggiarvi con un intero gruppo di codice.
Come si progettano combinatori efficaci?
Innanzitutto, pensa a quali operazioni hanno senso sui dati utilizzati dal tuo programma. Quindi pensa a come queste operazioni possono essere combinate in modo significativo in modi generici, nonché a come le operazioni possono essere suddivise in parti più piccole che sono collegate tra loro. La cosa principale è lavorare con trasformazioni e operazioni , non azioni dirette . Quando hai una funzione che esegue solo alcune complicate funzionalità in modo opaco e sputa solo una sorta di risultato pre-digerito, non c'è molto che puoi fare con quello. Lascia i risultati finali al codice che utilizza i combinatori: vuoi cose che ti portino dal punto A al punto B, non cose che si aspettano di essere l'inizio o la fine di un processo.
A cosa sono simili i combinatori in un linguaggio non funzionale (ad esempio Java) o cosa usano questi linguaggi al posto dei combinatori?
Ahahahaha. Divertente dovresti chiedere, perché gli oggetti sono davvero cose di ordine superiore in primo luogo - hanno alcuni dati, ma portano anche in giro un sacco di operazioni, e molto di ciò che costituisce un buon design OOP si riduce a "gli oggetti dovrebbero di solito agiscono come combinatori, non come strutture di dati ".
Quindi probabilmente la risposta migliore qui è che invece di cose simili a combinatori, usano classi con molti metodi getter e setter o campi pubblici, e la logica che consiste principalmente nel fare alcune azioni opache e predefinite.