¿Por qué el cuento popular y la ramda son tan diferentes?

96

Estoy aprendiendo FP de JavaScript leyendo el libro de DrBoolean .

Busqué una biblioteca de programación funcional. Encontré a Ramda y Folktale. Ambos afirman ser una biblioteca de programación funcional.

Pero son tan diferentes:

  • Ramda parece contener funciones de utilidad para lidiar con listas: mapear, reducir, filtrar y funciones puras: curry, componer. No contiene nada relacionado con la mónada, functor.

  • Sin embargo, Folktale no contiene ninguna utilidad para listas o funciones. Parece implementar algunas estructuras algebraicas en javascript como monad: Maybe, Task ...

En realidad encontré más bibliotecas, todas parecen caer en las dos categorías. El subrayado y lodash son como Ramda. La tierra de la fantasía, la fantasía sin sentido son como un cuento popular.

¿Pueden estas bibliotecas tan diferentes ser llamadas funcionales y, de ser así, qué hace que cada una sea una biblioteca funcional?

Aaron Shen
fuente
1
use lo que se adapte a sus necesidades y estilo y esté bien documentado
charlietfl
1
He descubierto que en realidad hay tres significados comúnmente utilizados para "programación funcional", especialmente en JS. 1. Uso de funciones puras de orden superior en conjuntos como matrices., Ej. [1,2,3].map(fnSquare).reduce(fnSum)2. Estructuras en gran parte académicas "look ma no var " Y-combinator-esque. 3. usar Function.prototypepara modificar el comportamiento de otras funciones, comovar isMissingID=fnContains.partial("id").negate();
dandavis
10
Un autor de Ramda aquí: Ramda es una biblioteca de utilidades de nivel bastante bajo. Su objetivo es simplificar cierto estilo funcional en JS, especialmente trabajando componiendo funciones. Ramda funciona bien con la especificación FantasyLand, incluidas sus implementaciones como Folktale. Esas bibliotecas están diseñadas para un propósito algo diferente. Se basan en el reconocimiento de tipos de datos abstractos comunes y permiten un acceso constante a ellos: cosas como Monoides, Functores y Mónadas. Ramda trabajará con ellos y tiene un proyecto paralelo para crear algunos, pero es, como dices, un enfoque muy diferente.
Scott Sauyet
1
@KeithNicholas: Sí, hay una habitación Gitter
Scott Sauyet
2
Echa un vistazo también a Sanctuary: github.com/plaid/sanctuary Esto se basa en ramda pero también cubre los tipos de tierras de fantasía.
arcseldon

Respuestas:

180

Características funcionales

No existe un límite claro de lo que define la programación funcional o una biblioteca funcional. Algunas características de los lenguajes funcionales están integradas en Javascript:

  • Funciones de primera clase y de orden superior
  • Funciones Lambdas / Anónimas, con cierres

Otros son posibles de lograr en Javascript con cierto cuidado:

  • Inmutabilidad
  • Transparencia referencial

Otros son parte de ES6 y están disponibles total o parcialmente en este momento:

  • Funciones compactas, incluso concisas
  • Recursividad performante a través de la optimización de la cola

Y hay muchos otros que están realmente más allá del alcance normal de Javascript:

  • La coincidencia de patrones
  • Evaluación perezosa
  • Homoiconicidad

Una biblioteca, entonces, puede elegir qué tipo de características está tratando de admitir y aún así, razonablemente, llamarse "funcionales".

Especificación de la tierra de la fantasía

Fantasy-land es una especificación para varios tipos estándar transferidos desde la teoría de categorías matemáticas y el álgebra abstracta a la programación funcional, tipos como Monoid , Functor y Monad . Estos tipos son bastante abstractos y amplían posiblemente nociones más familiares. Los functores, por ejemplo, son contenedores que se pueden mapsobrepasar con una función, de la misma forma en que se puede mapsobrepasar una matriz Array.prototype.map.

Cuento popular

Folktale es una colección de tipos que implementan varias partes de la especificación Fantasy-land y una pequeña colección de funciones de utilidad complementarias. Estos tipos son cosas como Quizás , O bien , Tarea (muy similar a lo que en otros lugares se llama Futuro y un primo más legal de una Promesa) y Validación

Folktale es quizás la implementación más conocida de la especificación Fantasy-land, y es muy respetada. Pero no existe una implementación definitiva o predeterminada; Fantasy-land solo especifica tipos abstractos, y una implementación, por supuesto, debe crear tales tipos concretos. La afirmación de Folktale de ser una biblioteca funcional es clara: proporciona tipos de datos que se encuentran típicamente en lenguajes de programación funcionales, que hacen que sea sustancialmente más fácil programar de manera funcional.

Este ejemplo, de la documentación de Folktale ( nota : no en las versiones recientes de los documentos), muestra cómo podría usarse:

// 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 (descargo de responsabilidad: soy uno de los autores) es un tipo de biblioteca muy diferente. No le proporciona nuevos tipos. 1 En cambio, proporciona funciones para facilitar la operación en tipos existentes. Se basa en las nociones de componer funciones más pequeñas en funciones más grandes, de trabajar con datos inmutables, de evitar efectos secundarios.

Ramda opera especialmente en listas, pero también en objetos y, a veces, en cadenas. También delega muchas de sus llamadas de tal manera que interoperará con Folktale u otras implementaciones de Fantasy-land. Por ejemplo, la mapfunción de Ramda opera de manera similar a la de encendido Array.prototype, entonces R.map(square, [1, 2, 3, 4]); //=> [1, 4, 9, 16]. Pero debido a que Folktale's Maybeimplementa la Functorespecificación Fantasy-land , que también especifica el mapa, también puedes usar la de Ramda mapcon ella:

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

Las afirmaciones de Ramda de ser una biblioteca funcional radican en facilitar la composición de funciones, nunca mutar sus datos y presentar solo funciones puras. El uso típico de Ramda sería desarrollar funciones más complejas componiendo funciones más pequeñas, como se ve en un artículo sobre la filosofía de Ramda.

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

Otras bibliotecas

En realidad encontré más bibliotecas, todas parecen caer en las dos categorías. subrayado, lodash son muy parecidos a Ramda. La tierra de la fantasía, la fantasía sin sentido son como un cuento popular.

Eso no es realmente exacto. En primer lugar, Fantasy-land es simplemente una especificación que las bibliotecas pueden decidir implementar para varios tipos. Folktale es una de las muchas implementaciones de esa especificación, probablemente la mejor completa, sin duda una de las más maduras. Pointfree-fantasy y ramda-fantasy son otros, y hay muchos más .

Subrayado y lodash son superficialmente como Ramda en el sentido de que son bibliotecas de bolsa de mano, que proporcionan una gran cantidad de funciones con mucha menos cohesión que algo como Folktale. E incluso la funcionalidad específica a menudo se superpone con la de Ramda. Pero a un nivel más profundo, Ramda tiene preocupaciones muy diferentes de esas bibliotecas. Primos más cercanos de Ramda son probablemente las bibliotecas como FKit , Fnuc y Wu.js .

Bilby está en una categoría propia, proporcionando tanto una serie de herramientas como las proporcionadas por Ramda como algunos tipos compatibles con Fantasy-land. (El autor de Bilby es el autor original de Fantasy-land también).

Tu llamada

Todas estas bibliotecas tienen derecho a ser llamadas funcionales, aunque varían mucho en el enfoque funcional y el grado de compromiso funcional.

Algunas de estas bibliotecas funcionan bien juntas. Ramda debería funcionar bien con Folktale u otras implementaciones de Fantasy-land. Dado que sus preocupaciones apenas se superponen, realmente no entran en conflicto, pero Ramda hace lo suficiente para que la interoperación sea relativamente fluida. Esto probablemente sea menos cierto para algunas de las otras combinaciones que podría elegir, pero la sintaxis de función más simple de ES6 también puede aliviar parte del dolor de la integración.

La elección de la biblioteca, o incluso el estilo de la biblioteca a utilizar, dependerá de su proyecto y sus preferencias. Hay muchas buenas opciones disponibles, y los números están creciendo y muchas de ellas están mejorando enormemente. Es un buen momento para hacer programación funcional en JS.


1 Bueno, hay un proyecto paralelo, ramda-fantasy que hace algo similar a lo que hace Folktale, pero no es parte de la biblioteca principal.

Scott Sauyet
fuente
1
¿Sería justo decir que ES6 tiene la capacidad de evaluación perezosa con la introducción de Yield? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Marcel Lamothe
8
No. yieldfacilita el tipo de procesamiento de listas diferido realizado por Lazyo lz.js. Pero no ayuda con la pereza a nivel del idioma. someFunc(a + b)en JS primero agrega los valores de ay bluego proporciona ese resultado como parámetro a someFunc. El equivalente en Haskell no hace eso. Si la función llamada nunca usa ese valor, nunca realiza la suma. Si finalmente lo usa, se considera una expresión a calcular hasta que se necesite su resultado. Si nunca hace nada que lo fuerce (como IO), nunca realizará el cálculo.
Scott Sauyet
@ScottSauyet quizá se podría argumentar "la evaluación perezosa" en alguna forma está disponible a través de generadores ES6 por ejemplo - un montón de marcos JS tiene características "pereza" - RxJs, etc. ImmutableJs
arcseldon
8
Esta respuesta debería ser un capítulo o sección del libro de DrBoolean. :)
Set
1
La documentación de Ramda tiende a usar "lista" como una forma abreviada de lo más parecido que ofrece JS a listas, matrices densas. Estos tienen características de rendimiento diferentes a las listas puras y, por supuesto, una API algo diferente, pero se pueden usar para los mismos propósitos, y son el tipo nativo más cercano (pero consulte github.com/funkia/list ) disponible para Ramda. API, que conceptualmente quiere trabajar con listas puras. Yo diría que el punto de las matrices no es cierto, ya que las matrices de estilo C no son más canónicas que las de JS, y ninguna se acerca mucho a las matemáticas, pero ese es un punto menor.
Scott Sauyet