perché il racconto popolare e la ramda sono così diversi?


96

Sto imparando javascript FP leggendo il libro di DrBoolean .

Ho cercato in giro per la libreria di programmazione funzionale. Ho trovato Ramda e Folktale. Entrambi affermano di essere una libreria di programmazione funzionale.

Ma sono così diversi:

  • Ramda sembra contenere funzioni di utilità per la gestione di list: map, reduce, filter e pure functions: curry, compose. Non contiene niente che abbia a che fare con la monade, funtore.

  • Folktale tuttavia non contiene alcuna utilità per elenchi o funzioni. Sembra implementare alcune strutture algebriche in javascript come monad: forse, attività ...

In realtà ho trovato più biblioteche, sembrano tutte rientrare nelle due categorie. Il carattere di sottolineatura e il lodash sono come Ramda. La terra della fantasia, la fantasia senza punti sono come un racconto popolare.

Queste librerie molto diverse possono essere entrambe chiamate funzionali e, in tal caso, cosa rende ognuna una libreria funzionale?


1
usa ciò che si adatta alle tue esigenze e al tuo stile ed è ben documentato
charlietfl

1
Ho scoperto che ci sono davvero tre significati comunemente intesi per "programmazione funzionale", specialmente in JS. 1. utilizzo di funzioni pure di ordine superiore su insiemi come array., Ex [1,2,3].map(fnSquare).reduce(fnSum)2. strutture "look ma no var " perlopiù accademiche . 3. utilizzo Function.prototypeper modificare il comportamento di altre funzioni, comevar isMissingID=fnContains.partial("id").negate();
dandavis

10
Un autore di Ramda qui: Ramda è una libreria di utilità di livello piuttosto basso. Ha lo scopo di rendere più semplice un certo stile funzionale in JS, in particolare lavorando componendo funzioni. Ramda funziona bene con la specifica FantasyLand, comprese le sue implementazioni come Folktale. Queste librerie sono progettate per uno scopo leggermente diverso. Sono costruiti attorno al riconoscimento di tipi di dati astratti comuni e consentendo un accesso coerente ad essi: cose come monoidi, funtori e monadi. Ramda lavorerà con loro e ha un progetto parallelo per crearne alcuni, ma è, come dici tu, un obiettivo molto diverso.
Scott Sauyet

1
@KeithNicholas: Sì, c'è una stanza Gitter
Scott Sauyet

2
Dai un'occhiata anche a Sanctuary - github.com/plaid/sanctuary Questo è basato su ramda ma copre anche i tipi di fantasy-land.
arcseldon

Risposte:


180

Caratteristiche funzionali

Non esiste un confine netto di ciò che definisce la programmazione funzionale o una libreria funzionale. Alcune caratteristiche dei linguaggi funzionali sono incorporate in Javascript:

  • Funzioni di prima classe e di ordine superiore
  • Funzioni Lambdas / Anonimo, con chiusure

Altri sono possibili da realizzare in Javascript con una certa cura:

  • Immutabilità
  • Trasparenza referenziale

Altri ancora fanno parte di ES6 e sono disponibili parzialmente o completamente al momento:

  • Funzioni compatte, persino concise
  • Ricorsione performante attraverso l'ottimizzazione della chiamata di coda

E ce ne sono molti altri che sono davvero oltre la normale portata di Javascript:

  • Corrispondenza del modello
  • Valutazione pigra
  • Omoiconicità

Una libreria, quindi, può scegliere quali tipi di funzionalità sta cercando di supportare e ancora essere ragionevolmente chiamata "funzionale".

Specifica della terra di fantasia

Fantasy-land è una specifica per un certo numero di tipi standard portati dalla teoria matematica delle categorie e dall'algebra astratta alla programmazione funzionale, tipi come Monoid , Functor e Monad . Questi tipi sono abbastanza astratti ed estendono nozioni forse più familiari. I funtori, ad esempio, sono contenitori che possono essere maptrasferiti con una funzione, nello stesso modo in cui un array può essere maputilizzato Array.prototype.map.

Folktale

Folktale è una raccolta di tipi che implementano varie parti della specifica Fantasy-land e una piccola raccolta di funzioni di utilità complementare. Questi tipi sono cose come Forse , Entrambi , Attività (molto simile a quello che altrove è chiamato Futuro e un cugino più legale di una Promessa) e Convalida

Folktale è forse l'implementazione più nota della specifica Fantasy-land ed è ben rispettata. Ma non esiste un'implementazione definitiva o predefinita; fantasy-land specifica solo tipi astratti, e un'implementazione ovviamente deve creare tali tipi concreti. L'affermazione di Folktale di essere una libreria funzionale è chiara: fornisce tipi di dati che si trovano tipicamente nei linguaggi di programmazione funzionale, quelli che rendono sostanzialmente più facile programmare in modo funzionale.

Questo esempio, dalla documentazione di Folktale ( nota : non nelle versioni recenti dei documenti), mostra come potrebbe essere utilizzato:

// We load the library by "require"-ing it
var Maybe = require('data.maybe')

// Returns Maybe.Just(x) if some `x` passes the predicate test
// Otherwise returns Maybe.Nothing()
function find(predicate, xs) {
  return xs.reduce(function(result, x) {
    return result.orElse(function() {
      return predicate(x)?    Maybe.Just(x)
      :      /* otherwise */  Maybe.Nothing()
    })
  }, Maybe.Nothing())
}

var numbers = [1, 2, 3, 4, 5]

var anyGreaterThan2 = find(function(a) { return a > 2 }, numbers)
// => Maybe.Just(3)

var anyGreaterThan8 = find(function(a) { return a > 8 }, numbers)
// => Maybe.Nothing

Ramda

Ramda (disclaimer: sono uno degli autori) è un tipo di libreria molto diverso. Non fornisce nuovi tipi per te. 1 Fornisce invece funzioni per semplificare le operazioni sui tipi esistenti. È costruito attorno alle nozioni di comporre funzioni più piccole in funzioni più grandi, di lavorare con dati immutabili, di evitare effetti collaterali.

Ramda opera soprattutto sugli elenchi, ma anche sugli oggetti e talvolta sulle stringhe. Delega anche molte delle sue chiamate in modo tale da interagire con Folktale o altre implementazioni di Fantasy-land. Ad esempio, la mapfunzione di Ramda , funziona in modo simile a quella su Array.prototype, quindi R.map(square, [1, 2, 3, 4]); //=> [1, 4, 9, 16]. Ma poiché Folktale Maybeimplementa la specifica Fantasy-land Functor, che specifica anche la mappa, puoi anche usare Ramda's mapcon essa:

R.map(square, Maybe.Just(5)); //=> Maybe.Just(25);
R.map(square, Maybe.Nothing); //=> Maybe.Nothing

Le affermazioni di Ramda di essere una libreria funzionale stanno nel rendere facile comporre funzioni, non mutare mai i dati e presentare solo funzioni pure. L'uso tipico di Ramda sarebbe costruire funzioni più complesse componendone di più piccole, come si vede in un articolo sulla filosofia di Ramda

// :: [Comment] -> [Number]  
var userRatingForComments = R.pipe(
    R.pluck('username')      // [Comment] -> [String]
    R.map(R.propOf(users)),  // [String] -> [User]
    R.pluck('rating'),       // [User] -> [Number]
);

Altre biblioteche

In realtà ho trovato più librerie, sembrano tutte rientrare nelle due categorie. sottolineatura, i lodash sono molto simili a Ramda. La terra della fantasia, la fantasia senza punti sono come un racconto popolare.

Non è proprio accurato. Prima di tutto, Fantasy-land è semplicemente una specifica che le biblioteche possono decidere di implementare per vari tipi. Folktale è una delle tante implementazioni di quella specifica, probabilmente la più completa, sicuramente una delle più mature. La fantasia senza punti e la fantasia ramda sono altre, e ce ne sono molte altre .

Underscore e lodash sono superficialmente come Ramda in quanto sono librerie a portata di mano, che forniscono un gran numero di funzioni con molta meno coesione rispetto a qualcosa come Folktale. E anche la funzionalità specifica spesso si sovrappone a quella di Ramda. Ma a un livello più profondo, Ramda ha preoccupazioni molto diverse da quelle biblioteche. Cugini più stretti di Ramda sono probabilmente librerie come FKit , Fnuc , e Wu.js .

Bilby è in una categoria a sé stante, fornendo sia una serie di strumenti come quelli forniti da Ramda sia alcuni tipi coerenti con Fantasy-land. (L'autore di Bilby è anche l'autore originale di Fantasy-land.)

La tua chiamata

Tutte queste librerie hanno il diritto di essere chiamate funzionali, sebbene differiscano notevolmente nell'approccio funzionale e nel grado di impegno funzionale.

Alcune di queste librerie funzionano effettivamente bene insieme. Ramda dovrebbe funzionare bene con Folktale o altre implementazioni di Fantasy-land. Dal momento che le loro preoccupazioni si sovrappongono a malapena, in realtà non sono in conflitto, ma Ramda fa quel tanto che basta per rendere l'interoperabilità relativamente agevole. Questo è probabilmente meno vero per alcune delle altre combinazioni che potresti scegliere, ma la sintassi della funzione più semplice di ES6 potrebbe anche eliminare parte del problema dell'integrazione.

La scelta della libreria, o anche dello stile della libreria da utilizzare, dipenderà dal tuo progetto e dalle tue preferenze. Sono disponibili molte buone opzioni e i numeri stanno crescendo e molte di esse stanno migliorando notevolmente. È un buon momento per fare programmazione funzionale in JS.


1 Bene, c'è un progetto secondario , ramda-fantasy che fa qualcosa di simile a quello che fa Folktale, ma non fa parte della libreria principale.


1
Sarebbe giusto dire che ES6 ha la capacità di una valutazione pigra con l'introduzione di Yield? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Marcel Lamothe

8
No. yieldrende più facile eseguire il tipo di elaborazione delle liste pigre eseguita da Lazyo lz.js. Ma non aiuta con la pigrizia a livello linguistico. someFunc(a + b)in JS prima aggiunge i valori di ae bpoi fornisce quel risultato come parametro a someFunc. L'equivalente in Haskell non lo fa. Se la funzione chiamata non usa mai quel valore, non esegue mai l'addizione. Se alla fine lo utilizza, è considerata un'espressione da calcolare fino a quando non è necessario il suo risultato. Se non fai mai nulla che lo costringa (come IO), non eseguirà mai effettivamente il calcolo.
Scott Sauyet

@ScottSauyet forse potresti sostenere che la "valutazione pigra" in qualche forma sia disponibile tramite i generatori ES6, ad esempio - molti framework JS hanno caratteristiche di "pigrizia" - RxJs, ImmutableJs ecc.
arcseldon

8
Questa risposta dovrebbe essere un capitolo o una sezione nel libro di DrBoolean. :)
Seth

1
La documentazione di Ramda tende a usare "list" come abbreviazione per la cosa più vicina che JS offre agli elenchi, agli array densi. Questi hanno caratteristiche di prestazione diverse rispetto agli elenchi puri e, naturalmente, un'API un po 'diversa, ma possono essere utilizzati per quasi gli stessi scopi e sono il tipo nativo più vicino (ma vedi github.com/funkia/list ) disponibile per Ramda API, che concettualmente vuole lavorare con liste pure. Direi che il punto degli array non veri, poiché gli array in stile C non sono più canonici di quelli JS e nessuno si avvicina molto a quelli matematici, ma questo è un punto minore.
Scott Sauyet
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.