dlaczego podania ludowe i ramda są tak różne?

97

Uczę się javascript FP, czytając książkę DrBoolean .

Szukałem biblioteki programowania funkcjonalnego. Znalazłem Ramdę i Folktale. Obie twierdzą, że są funkcjonalną biblioteką programowania.

Ale są tak różni:

  • Ramda wydaje się zawierać funkcje użytkowe do obsługi list: mapowania, redukcji, filtrowania i czyste funkcje: curry, compose. Nie zawiera nic do czynienia z monadą, funktorem.

  • Folktale nie zawiera jednak żadnego narzędzia do listy lub funkcji. Wydaje się, że implementuje niektóre struktury algebraiczne w javascript, takie jak monada: Może, zadanie ...

Właściwie znalazłem więcej bibliotek, wszystkie wydają się należeć do dwóch kategorii. Podkreślenie i lodash są jak Ramda. Fantasy-land, pointfree-fantasy są jak legenda.

Czy te bardzo różne biblioteki można nazwać funkcjonalnymi , a jeśli tak, to co sprawia, że ​​każda z nich jest biblioteką funkcjonalną?

Aaron Shen
źródło
1
używaj tego, co pasuje do twoich potrzeb i stylu i jest dobrze udokumentowane
charlietfl
1
Odkryłem, że istnieją naprawdę trzy powszechnie stosowane znaczenia dla „programowania funkcjonalnego”, szczególnie w JS. 1. używanie czystych funkcji wyższego rzędu na zestawach, takich jak tablice., Np. [1,2,3].map(fnSquare).reduce(fnSum)2. w dużej mierze akademickie struktury typu „look ma no var ” w układzie Y-kombinator. 3. używanie Function.prototypedo modyfikowania zachowania innych funkcji, takich jakvar isMissingID=fnContains.partial("id").negate();
dandavis
11
Autor Ramdy tutaj: Ramda jest biblioteką narzędzi dość niskiego poziomu. Ma to na celu uproszczenie pewnego stylu funkcjonalnego w JS, zwłaszcza poprzez tworzenie funkcji. Ramda dobrze współpracuje ze specyfikacją FantasyLand, włączając w to jej implementacje, takie jak Folktale. Te biblioteki są zaprojektowane w nieco innym celu. Opierają się na rozpoznawaniu typowych abstrakcyjnych typów danych i zapewnianiu spójnego dostępu do nich: takich rzeczy jak Monoidy, Funktory i Monady. Ramda będzie z nimi współpracować i ma poboczny projekt, aby stworzyć niektóre, ale jest to, jak powiedziałeś, bardzo inny cel.
Scott Sauyet
1
@KeithNicholas: Tak, jest pokój
Gittera
2
Spójrz też na Sanctuary - github.com/plaid/sanctuary Jest to oparte na ramdzie, ale obejmuje również typy fantasy-land.
arcseldon

Odpowiedzi:

182

Funkcje funkcjonalne

Nie ma wyraźnej granicy tego, co definiuje programowanie funkcjonalne lub bibliotekę funkcjonalną. Niektóre funkcje języków funkcjonalnych są wbudowane w Javascript:

  • Funkcje pierwszorzędne, wyższego rzędu
  • Funkcje Lambdy / Anonymous z zamknięciami

Inne są możliwe do wykonania w JavaScript z pewną ostrożnością:

  • Niezmienność
  • Referencyjna przejrzystość

Jeszcze inne są częścią ES6 i są teraz częściowo lub w pełni dostępne:

  • Kompaktowe, a nawet zwięzłe funkcje
  • Wydajna rekurencja dzięki optymalizacji wywołań ogonowych

Jest też wiele innych, które są naprawdę poza normalnym zasięgiem Javascript:

  • Dopasowanie wzorców
  • Leniwa ocena
  • Homoikoniczność

Biblioteka może więc wybierać, jakie rodzaje funkcji próbuje obsługiwać i nadal rozsądnie nazywać ją „funkcjonalną”.

Specyfikacja krainy fantasy

Fantasy-land to specyfikacja wielu standardowych typów przeniesionych z matematycznej teorii kategorii i algebry abstrakcyjnej do programowania funkcjonalnego, takich jak Monoid , Functor i Monad . Te typy są dość abstrakcyjne i rozszerzają prawdopodobnie bardziej znane pojęcia. Na przykład funktory to kontenery, które można mapprzerzucić za pomocą funkcji, tak jak tablica może być mapprzerzucona za pomocą funkcji Array.prototype.map.

Folktale

Folktale to zbiór typów implementujących różne części specyfikacji Fantasy-land oraz niewielki zbiór towarzyszących funkcji użytkowych. Typy te są rzeczy podoba Może , albo , zadanie (bardzo podobny do tego, co gdzie indziej nazywa się przyszłości, a bardziej legalny kuzyn obietnicę), a Validation

Folktale jest prawdopodobnie najbardziej znaną implementacją specyfikacji Fantasy-land i cieszy się dużym uznaniem. Ale nie ma czegoś takiego jak ostateczna lub domyślna implementacja; Fantasy-land określa tylko typy abstrakcyjne, a implementacja musi oczywiście tworzyć takie konkretne typy. Twierdzenie Folktale o byciu biblioteką funkcjonalną jest jasne: dostarcza typów danych spotykanych zwykle w funkcjonalnych językach programowania, które znacznie ułatwiają programowanie w sposób funkcjonalny.

Ten przykład z dokumentacji Folktale ( uwaga : nie w ostatnich wersjach dokumentacji) pokazuje, jak można go użyć:

// 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 (zastrzeżenie: jestem jednym z autorów) to zupełnie inny rodzaj biblioteki. Nie zapewnia nowych typów. 1 Zamiast tego zapewnia funkcje ułatwiające obsługę istniejących typów. Opiera się na pojęciach łączenia mniejszych funkcji w większe, pracy z niezmiennymi danymi, unikania skutków ubocznych.

Ramda działa szczególnie na listach, ale także na obiektach, a czasami na łańcuchach. Przekazuje również wiele swoich wywołań w taki sposób, że będzie współpracować z Folktale lub innymi implementacjami Fantasy-land. Na przykład mapfunkcja Ramdy działa podobnie do funkcji na Array.prototype, więc R.map(square, [1, 2, 3, 4]); //=> [1, 4, 9, 16]. Ale ponieważ Folktale Maybeimplementuje specyfikację Fantasy-land Functor, która określa również mapę, możesz również użyć mapz nią Ramdy :

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

Ramda twierdzi, że jest biblioteką funkcjonalną, ponieważ ułatwia tworzenie funkcji, nigdy nie mutuje danych i przedstawia tylko czyste funkcje. Typowym zastosowaniem Ramdy byłoby zbudowanie bardziej złożonej funkcji poprzez komponowanie mniejszych, jak widać w artykule o filozofii Ramdy

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

Inne biblioteki

Właściwie znalazłem więcej bibliotek, wszystkie wydają się należeć do dwóch kategorii. podkreślenie, lodash są bardzo podobne do Ramdy. Fantasy-land, pointfree-fantasy są jak legenda.

To nie jest do końca dokładne. Przede wszystkim Fantasy-land to po prostu specyfikacja, którą biblioteki mogą zdecydować się zaimplementować dla różnych typów. Folktale to jedna z wielu implementacji tej specyfikacji, chyba najlepiej dopracowana, na pewno jedna z najbardziej dojrzałych. Pointfree-fantasy i ramda-fantasy to inne, a jest ich znacznie więcej .

Podkreślenie i lodash są z pozoru podobne do Ramdy, ponieważ są bibliotekami typu `` grab-bag '', dostarczającymi wielu funkcji o znacznie mniejszej spójności niż coś takiego jak Folktale. A nawet specyficzna funkcjonalność często pokrywa się z Ramdą. Ale na głębszym poziomie Ramda ma zupełnie inne obawy niż te biblioteki. Najbliższymi kuzynami Ramdy są prawdopodobnie biblioteki takie jak FKit , Fnuc i Wu.js .

Bilby to osobna kategoria, która zapewnia zarówno szereg narzędzi, takich jak te dostarczone przez Ramdę, jak i niektóre typy zgodne z Fantasy-land. (Autor Bilby jest również oryginalnym autorem Fantasy-landu.)

Twoja decyzja

Wszystkie te biblioteki mają prawo nazywać się funkcjonalnymi, chociaż różnią się znacznie podejściem funkcjonalnym i stopniem zaangażowania funkcjonalnego.

Niektóre z tych bibliotek dobrze ze sobą współpracują. Ramda powinna dobrze współpracować z Folktale lub innymi implementacjami Fantasy-land. Ponieważ ich obawy ledwie się pokrywają, tak naprawdę nie są ze sobą sprzeczne, ale Ramda robi wszystko, co w ich mocy, aby zapewnić stosunkowo płynną współpracę. Jest to prawdopodobnie mniej prawdziwe w przypadku niektórych innych kombinacji, które możesz wybrać, ale prostsza składnia funkcji ES6 może również zmniejszyć ból związany z integracją.

Wybór biblioteki, a nawet stylu biblioteki będzie zależał od projektu i preferencji. Dostępnych jest wiele dobrych opcji, a ich liczba rośnie, a wiele z nich znacznie się poprawia. To dobry czas na programowanie funkcjonalne w JS.


1 Cóż, istnieje poboczny projekt, ramda-fantasy, który robi coś podobnego do tego, co robi Folktale, ale nie jest częścią podstawowej biblioteki.

Scott Sauyet
źródło
1
Czy byłoby uczciwie powiedzieć, że ES6 ma zdolność do leniwej oceny po wprowadzeniu Yield? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Marcel Lamothe
8
Nie. yieldUłatwia wykonywanie tego rodzaju leniwego przetwarzania list za pomocą Lazylub lz.js. Ale to nie pomaga w lenistwie na poziomie językowym. someFunc(a + b)w JS najpierw dodaje wartości, aa bnastępnie dostarcza wynik jako parametr do someFunc. Odpowiednik w Haskell tego nie robi. Jeśli wywołana funkcja nigdy nie używa tej wartości, nigdy nie wykonuje dodawania. Jeśli w końcu go użyje, uważa się, że wyrażenie jest obliczane, dopóki jego wynik nie będzie potrzebny. Jeśli nigdy nie zrobisz niczego, co wymusi to (jak IO), to nigdy nie wykona obliczeń.
Scott Sauyet
@ScottSauyet być może możesz argumentować, że "leniwa ocena" w jakiejś formie jest dostępna na przykład przez generatory ES6 - wiele frameworków JS ma cechy "lenistwa" - RxJs, ImmutableJs itp.
arcseldon
9
Ta odpowiedź powinna być rozdziałem lub sekcją w książce DrBoolean. :)
Seth
1
Dokumentacja Ramdy ma tendencję do używania „listy” jako skrótu dla rzeczy, które JS najbliżej oferuje listom, gęstych tablic. Mają one inną charakterystykę wydajności niż czyste listy i oczywiście nieco inny interfejs API, ale mogą być używane do tych samych celów i są najbliższym rodzimym typem (ale patrz github.com/funkia/list ) dostępnym dla Ramdy API, które koncepcyjnie chce pracować z czystymi listami. Twierdziłbym, że tablice nie są prawdziwe, ponieważ tablice w stylu C nie są bardziej kanoniczne niż tablice JS i nie są tak naprawdę zbliżone do matematycznych, ale to drobna uwaga.
Scott Sauyet