почему сказка и рамда такие разные?

97

Я изучаю javascript FP, читая книгу DrBoolean .

Я искал библиотеку функционального программирования. Я нашел Рамду и Сказку. Оба претендуют на звание библиотеки функционального программирования.

Но они такие разные:

  • Ramda, кажется, содержит служебные функции для работы со списком: карта, сокращение, фильтр и чистые функции: карри, составить. Он не содержит ничего, что могло бы иметь дело с монадой, функтором.

  • Folktale, однако, не содержит никаких утилит для списка или функций. Кажется, что в javascript реализованы некоторые алгебраические структуры, такие как монада: Может быть, Задача ...

На самом деле я нашел больше библиотек, все они, кажется, делятся на две категории. Подчеркивание и lodash подобны Рамде. Страна фэнтези, фэнтези без точек похожи на сказку.

Можно ли назвать обе эти очень разные библиотеки функциональными , и если да, то что делает каждую из них функциональной?

Аарон Шен
источник
1
используйте то, что соответствует вашим потребностям и стилю и хорошо задокументировано
charlietfl
1
Я обнаружил, что на самом деле существует три общепринятых значения «функционального программирования», особенно в JS. 1. использование чистых функций высшего порядка на множествах, таких как массивы. Пример [1,2,3].map(fnSquare).reduce(fnSum)2. в основном академические структуры типа Y-комбинатора "look ma no var ". 3. использование Function.prototypeдля изменения поведения других функций, напримерvar isMissingID=fnContains.partial("id").negate();
dandavis 08
11
Автор Ramda здесь: Ramda - это довольно низкоуровневая служебная библиотека. Он предназначен для упрощения определенного функционального стиля в JS, особенно для работы путем составления функций. Ramda хорошо работает со спецификацией FantasyLand, включая ее реализации, такие как Folktale. Эти библиотеки предназначены для несколько иной цели. Они построены на распознавании общих абстрактных типов данных и предоставлении последовательного доступа к ним: таким вещам, как моноиды, функторы и монады. Рамда будет работать с ними, и у него есть сторонний проект для их создания, но, как вы говорите, это совсем другой фокус.
Скотт Сойет
1
@KeithNicholas: Да, есть Gitter Room
Скотт Сойет
2
Взгляните также на Sanctuary - github.com/plaid/sanctuary. Он основан на ramda, но также охватывает типы фэнтезийных земель.
arcseldon

Ответы:

182

Функциональные особенности

Нет четкой границы того, что определяет функциональное программирование или функциональную библиотеку. Некоторые функции функциональных языков встроены в Javascript:

  • Первоклассные функции высшего порядка
  • Лямбда-выражения / анонимные функции с закрытием

Остальные можно выполнить с помощью Javascript с некоторой осторожностью:

  • Неизменность
  • Ссылочная прозрачность

Третьи являются частью ES6 и частично или полностью доступны прямо сейчас:

  • Компактные, даже лаконичные функции
  • Производительная рекурсия за счет оптимизации хвостового вызова

И есть много других, которые действительно выходят за рамки обычного Javascript:

  • Сопоставление с образцом
  • Ленивая оценка
  • Гомоиконность

Таким образом, библиотека может выбирать, какие функции она пытается поддерживать, и при этом называться «функциональными».

Спецификация фэнтезийной страны

Страна фантазий - это спецификация для ряда стандартных типов, перенесенных из математической теории категорий и абстрактной алгебры в функциональное программирование, таких как Monoid , Functor и Monad . Эти типы довольно абстрактны и, возможно, расширяют более знакомые понятия. Функторы, например, контейнеры , которые могут быть mapPED над функцией, то , как массив может быть mapPED по сравнению с использованием Array.prototype.map.

Сказка

Folktale - это набор типов, реализующих различные части спецификации Fantasy-land, и небольшой набор вспомогательных функций. Эти типы - это такие вещи, как Maybe , Either , Task (очень похоже на то, что в другом месте называется Future, и более законный родственник Promise) и Validation

Folktale - это, пожалуй, самая известная реализация спецификации Fantasy-land, и она пользуется большим уважением. Но не существует такой вещи, как окончательная реализация или реализация по умолчанию; Fantasy -land определяет только абстрактные типы, и реализация, конечно же, должна создавать такие конкретные типы. Претензия Folktale на то, чтобы быть функциональной библиотекой, очевидна: она предоставляет типы данных, обычно встречающиеся в языках функционального программирования, которые значительно упрощают функциональное программирование.

Этот пример из документации Folktale ( примечание : не в последних версиях документации) показывает, как его можно использовать:

// 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 (отказ от ответственности: я один из авторов) - это совершенно другой тип библиотеки. Он не предлагает вам новых типов. 1 Вместо этого он предоставляет функции, упрощающие работу с существующими типами. Он построен на принципах компоновки более мелких функций в более крупные, работы с неизменяемыми данными и предотвращения побочных эффектов.

Ramda работает в первую очередь со списками, но также и с объектами, а иногда и со строками. Он также делегирует многие из своих вызовов таким образом, чтобы он мог взаимодействовать с Folktale или другими реализациями Fantasy-Land. Например, mapфункция Ramda работает так же , как и функция Array.prototype, поэтому R.map(square, [1, 2, 3, 4]); //=> [1, 4, 9, 16]. Но поскольку Folktale Maybeреализует Functorспецификацию Fantasy-land , которая также определяет карту, вы также можете использовать mapс ней Ramda :

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

Заявления Ramda о том, что это функциональная библиотека, заключаются в упрощении компоновки функций, без изменения ваших данных и в представлении только чистых функций. Типичным использованием Ramda было бы создание более сложных функций путем составления более мелких, как показано в статье о философии Ramda.

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

Другие библиотеки

На самом деле я нашел больше библиотек, все они, кажется, делятся на две категории. подчеркиваю, lodash очень похожи на Ramda. Страна фэнтези, фэнтези без точек похожи на сказку.

Это не совсем так. Прежде всего, Fantasy-land - это просто спецификация, которую библиотеки могут решить реализовать для различных типов. Folktale - одна из многих реализаций этой спецификации, вероятно, наиболее полная и, безусловно, одна из самых зрелых. Безупречная фантазия и рамда-фэнтези - это другие, и их гораздо больше .

Underscore и lodash внешне похожи на Ramda в том смысле, что они представляют собой универсальные библиотеки, предоставляющие большое количество функций с гораздо меньшей согласованностью, чем что-то вроде Folktale. И даже определенные функции часто совпадают с функциональностью Ramda. Но на более глубоком уровне у Ramda совсем другие задачи, чем у этих библиотек. Близкие кузены Ramda являются , вероятно , библиотеки FKit , Fnuc и Wu.js .

Билби находится в отдельной категории, предоставляя как ряд инструментов, таких как предоставленные Ramda, так и некоторые типы, совместимые с Fantasy-land. (Автор Билби также является первоначальным автором Страны фантазий.)

Ваш звонок

Все эти библиотеки имеют право называться функциональными, хотя они сильно различаются по функциональному подходу и степени функциональной приверженности.

Некоторые из этих библиотек действительно хорошо работают вместе. Ramda должна хорошо работать с Folktale или другими реализациями Fantasy Land. Поскольку их проблемы почти не пересекаются, они действительно не конфликтуют, но Ramda делает ровно столько, чтобы взаимодействие было относительно гладким. Это, вероятно, менее верно для некоторых других комбинаций, которые вы могли бы выбрать, но более простой синтаксис функций ES6 также может облегчить интеграцию.

Выбор библиотеки или даже стиля ее использования будет зависеть от вашего проекта и ваших предпочтений. Доступно множество хороших вариантов, и их количество растет, и многие из них значительно улучшаются. Хорошее время заняться функциональным программированием на JS.


1 Ну, есть побочный проект ramda-fantasy, делающий что-то похожее на то, что делает Folktale, но он не является частью основной библиотеки.

Скотт Сойет
источник
1
Было бы справедливо сказать, что ES6 имеет возможность ленивого оценивания с введением Yield? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Марсель Ламот
8
Нет. yieldУпрощает выполнение ленивых операций со списками, выполняемых Lazyили lz.js. Но это не помогает с ленью языкового уровня. someFunc(a + b)в JS сначала добавляются значения, aа bзатем этот результат передается в качестве параметра someFunc. Эквивалент в Haskell этого не делает. Если вызываемая функция никогда не использует это значение, она никогда не выполняет сложение. Если он в конечном итоге его использует, он считается выражением, которое нужно вычислить, пока не потребуется его результат. Если вы никогда не сделаете ничего, что заставит его (например, ввод-вывод), он никогда не выполнит вычисления.
Скотт Сойет
@ScottSauyet, возможно, вы возразите, что «ленивая оценка» в той или иной форме доступна, например, через генераторы ES6 - многие фреймворки JS имеют характеристики «лени» - RxJs, ImmutableJs и т. Д.
arcseldon
9
Этот ответ должен быть главой или разделом книги DrBoolean. :)
Сет
1
Документация Ramda имеет тенденцию использовать «список» как сокращение для обозначения того, что JS предлагает наиболее близко к спискам, плотным массивам. У них другие характеристики производительности, чем чистые списки, и, конечно, несколько другой API, но они могут использоваться почти для тех же целей, и они являются ближайшим родным (но см. Github.com/funkia/list ) типом, доступным для Ramda. API, который концептуально хочет работать с чистыми списками. Я бы поспорил с неверной точкой зрения на массивы, поскольку массивы в стиле C не более каноничны, чем JS, и ни один из них не очень близок к математическим, но это второстепенный момент.
Скотт Сойет