Spiegazione dei combinatori per il lavoratore


93

Cos'è un combinatore?

È "una funzione o una definizione senza variabili libere" (come definito in SO)?

O che ne dici di questo: secondo John Hughes nel suo famoso articolo su Arrows, "un combinatore è una funzione che costruisce frammenti di programma da frammenti di programma" , il che è vantaggioso perché "... il programmatore che utilizza i combinatori costruisce gran parte del programma automaticamente, invece di scrivere ogni dettaglio a mano ". Continua dicendo che mape filtersono due esempi comuni di tali combinatori.

Alcuni combinatori che corrispondono alla prima definizione:

Alcuni combinatori che corrispondono alla seconda definizione:

  • carta geografica
  • filtro
  • piegare / ridurre (presumibilmente)
  • uno qualsiasi di >> =, compose, fmap ?????

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. Ecco alcune delle mie domande specifiche sui combinatori:

  1. Quali sono altri esempi di combinatori come map, filter?
  2. Quali combinatori implementano spesso i linguaggi di programmazione?
  3. In che modo i combinatori possono aiutarmi a progettare un'API migliore?
  4. Come si progettano combinatori efficaci?
  5. A cosa sono simili i combinatori in un linguaggio non funzionale (ad esempio Java) o cosa usano questi linguaggi al posto dei combinatori?

Aggiornare

Grazie a @CA McCann, ora ho una migliore comprensione dei combinatori. Ma una domanda è ancora un punto critico per me:

Qual è la differenza tra un programma funzionale scritto con e uno scritto senza un pesante uso di combinatori?

Sospetto che la risposta sia che la versione con combinatore è più breve, più chiara, più generale, ma apprezzerei una discussione più approfondita, se possibile.

Sto anche cercando più esempi e spiegazioni di combinatori complessi (cioè più complessi di fold) nei linguaggi di programmazione comuni.


4
Considero le funzioni map / filter / fold di ordine superiore e le uso sempre. Non ho ancora idea di cosa sia un combinatore.

1
@pst - Avrei accettato 5 giorni fa, ma ora non posso discutere con John Hughes
Matt Fenwick

Risposte:


93

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.


Bella risposta! Vediamo se ho capito: i combinatori non sono speciali, ma piuttosto parte integrante della costruzione di un sistema software manutenibile? Sto ancora cercando di assimilare l'affermazione "frammenti di programma" di Hughes, nel contesto del tuo post.
Matt Fenwick

@ Matt Fenwick: Sono abbastanza sicuro che stia usando solo "frammenti di programma" per indicare il tipo di trasformazioni / operazioni di cui sto parlando, in particolare se si tratta di "Frecce", che enfatizzano questo approccio ancora più fortemente. Inoltre, non direi che si tratta esattamente di costruire sistemi manutenibili , più di costruire sistemi altamente modulari e disaccoppiati in un modo particolare , con i vantaggi che ciò comporta.
CA McCann,

Conosci qualche buona risorsa per documentarti sull'uso pratico dei combinatori? Grazie mille!
Matt Fenwick

@ Matt Fenwick: Niente di specifico a questo nella mia testa, mi dispiace. Tuttavia, tende ad essere un approccio naturale per i programmi scritti in uno stile molto funzionale, quindi è sufficiente passare un po 'di tempo con linguaggi che lo incoraggiano fortemente (ad esempio, Haskell o Clojure) e osservare come il codice pulito e idiomatico è scritto in quella lingua , è un ottimo modo per avere un'idea dello stile.
CA McCann
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.