Ramda с типами FP

Недавно я решил перейти с lodash на ramda, чтобы поиграть с функциональным способом составления моей логики. Я люблю это! После некоторого тщательного изучения FP я обнаружил, что речь идет не только о удобных чистых/бесплатных утилитах (ramda), но и о сложных (по крайней мере, для меня) математических абстракциях (fantasy-land). Я не понимаю всего этого, но шаблон «Либо и задача» выглядит очень удобным. Проблема в том, что я не уверен, как объединить его с утилитами ramda. Я знаю о ramda-fantasy, но она больше не поддерживается. Предлагаемые Ramda-fantasy библиотеки работают не так, как ramda-fantasy. Со всей этой новой информацией о типах Monads/Monoids/Functors я полностью потерялся.

Например, какое соглашение для этого?

      Right('boo')
  .map(x => x + '!')
  .map(x => x.toUpperCase())

vs 

R.pipe(
  R.map(x => x + '!')
  R.map(x => x.toUpperCase())
)(Right('boo'))

Мне не нужна рамда, если я решу полностью перейти на монады?

1 ответ

Один из способов подумать об этом — подумать о типах и функциях.

Ramda предлагает большой набор служебных функций. Они работают с массивами, объектами, функциями, строками, числами и т. д. Но они также работают с пользовательскими типами. Итак, в вашем примере R.mapработает со всем, что соответствует спецификации Functor . Если реализация Eitherвы используете соответствие этой спецификации, тогда Ramda будет работать с ней.

Но Ramda не предоставляет типы . Он работает со встроенными типами, такими как Object, Array, Function и т. д. Но, возможно, вне Lens-- он не поставляет никаких собственных типов. Библиотеки, такие как Folktale, предоставляют большие коллекции типов, например Maybe, Result, Validation, Taskа также ; более специализированные, такие как Fluture, предоставляют мощные версии одного конкретного типа ( Future). Все эти типы реализуют спецификацию Functor. Очень неполный список таких реализаций предоставляет FantasyLand.

Эти два понятия, функции абстрактного типа и наборы типов, дополняют друг друга. Функция Ramda, которая работает с любым функтором, будет работать с любой используемой вами версией Либо (при условии, что она соответствует спецификации). Подробнее об этой взаимосвязи см. в этом StackOverflow Q+A.

В вопросе сравнивались эти два фрагмента:

      Right('boo')
  .map(x => x + '!')
  .map(x => x.toUpperCase())

а также

      R.pipe(
  R.map(x => x + '!')
  R.map(x => x.toUpperCase())
)(Right('boo'))

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

Если бы мы написали эту функцию:

      const bigBang = pipe(
  map (x => x + '!'),
  map (x => x .toUpperCase ())
)

или возможно эта версия

      const bigBang = pipe (
  map (concat (__, '!')),
  map (toUpper)
)

Затем эта функция теперь доступна для использования на многих типах. Например:

      bigBang (['boo', 'scared', 'you'])     //=> ['BOO!', 'SCARED!', 'YOU!']
bigBang ({a: 'boo', b: 'ya'})          //=> {a: 'BOO!', b: 'YA!}
bigBang ((s) => s .repeat (2)) ('boo') //=> 'BOOBOO!'
bigBang (Right ('boo'))                //=> Right ('BOO!') 
bigBang (Left ('oops'))                //=> Left ('oops') 
bigBang (Just ('boo'))                 //=> Just ('BOO!') 
bigBang (Nothing())                    //=> Nothing ()
bigBang (Future ('boo'))               //=> Future ('BOO!')

Первые три реализации — массив, объект и функция — предоставляются Ramda. Но остальные по-прежнему работают, поскольку Ramda взаимодействует со спецификацией FantasyLand Functor. И это будет работать, если вы предоставите свой собственный mapметод на вашем типе (или даже лучше fantasy-land/mapметод.)

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

Другие вопросы по тегам