Как трубы и монады работают вместе в JavaScript?

Я посмотрел на подобные вопросы и ответы и не нашел ответа, который напрямую затрагивает мой вопрос. Я изо всех сил пытаюсь понять, как использовать Maybe или Either или Monads в сочетании с функциями трубопровода. Я хочу объединить функции вместе, но я хочу, чтобы труба остановилась и возвратила ошибку, если она возникает на любом этапе. Я пытаюсь реализовать концепции функционального программирования в приложении node.js, и это действительно мое первое серьезное исследование, так что ответ не будет таким простым, чтобы оскорбить мой интеллект по этому вопросу.

Я написал такую ​​функцию:

 const _pipe = (f, g) => async (...args) => await g( await f(...args)) module.exports = {arguments. pipeAsync: async (...fns) => { return await fns.reduce(_pipe) }, ... 

Я называю это так:

  const token = await utils.pipeAsync(makeACall, parseAuthenticatedUser, syncUserWithCore, managejwt.maketoken)(x, y) 

крюк, линия и грузило

Я не могу подчеркнуть, насколько критически важно, чтобы вы не зацепились за все новые термины, которые, как вы должны учиться, – функциональное программирование – это функции – и, возможно, единственное, что вам нужно понять о функции, это то, что она позволяет вам абстрагировать часть вашей программы с помощью параметра; или несколько параметров, если это необходимо (это не так) и поддерживается вашим языком (обычно это)

Почему я говорю вам это? Ну, JavaScript уже имеет совершенно хороший API для асинхронных функций Promise.prototype.then с использованием встроенного Promise.prototype.then

 // never reinvent the wheel   const _pipe = (f, g) => async (... args) => ждать g (ожидание f (... args)) 
 myPromise.then (f). then (g). then (h) ... 

Но вы хотите написать функциональные программы, не так ли? Это не проблема для функционального программиста. Изолируйте поведение, которое вы хотите абстрагировать (скрыть), и просто оберните его в параметризованную функцию – теперь, когда у вас есть функция, возобновите запись своей программы в функциональном стиле …

После того, как вы это сделаете некоторое время, вы начнете замечать шаблоны абстракции – эти шаблоны будут использоваться в качестве вариантов использования для всех других вещей (функторы, аппликаторы, монады и т. Д.), О которых вы узнаете позже, – но сохраните их позже – для теперь функции

Ниже мы демонстрируем слева-направо состав асинхронных функций через comp . Для целей этой программы delay включается в качестве создателя обещаний, а sq и add1 – пример асинхронных функций.

 const delay = (ms, x) => new Promise (r => setTimeout (r, ms, x)) const sq = async x => delay (1000, x * x) const add1 = async x => delay (1000, x + 1) // just make a function const comp = (f,g) => // abstract away the sickness x => f (x) .then (g) // resume functional programming comp (sq, add1) (10) // this effect added for demo purposes .then (console.log, console.error) // 2 seconds later... // 101 

Ответ наомика очень интересный, но похоже, что она действительно не могла ответить на ваш вопрос.

Короткий ответ заключается в том, что ваша функция _pipe распространяется на ошибки просто отлично. И останавливает выполнение функций, как только выдается ошибка.

Проблема заключается в вашей функции pipeAsync , где у вас есть правильная идея, но вы, разумеется, не должны возвращать promise для функции вместо функции.

Вот почему вы не можете этого сделать, потому что каждый раз он выдает ошибку:

 const result = await pipeAsync(func1, func2)(a, b); 

Чтобы использовать pipeAsync в своем текущем состоянии, вам нужно два await : один, чтобы получить результат pipeAsync а другой – получить результат вызова этого результата:

 const result = await (await pipeAsync(func1, func2))(a, b); 

Решение

Удалите ненужное async и pipeAsync от определения pipeAsync . Акт создания ряда функций, даже асинхронных функций, не является асинхронной операцией:

 module.exports = { pipeAsync: (...fns) => fns.reduce(_pipe), 

Как только вы это сделаете, все работает красиво:

 const _pipe = (f, g) => async(...args) => await g(await f(...args)) const pipeAsync = (...fns) => fns.reduce(_pipe); const makeACall = async(a, b) => a + b; const parseAuthenticatedUser = async(x) => x * 2; const syncUserWithCore = async(x) => { throw new Error("NOOOOOO!!!!"); }; const makeToken = async(x) => x - 3; (async() => { const x = 9; const y = 7; try { // works up to parseAuthenticatedUser and completes successfully const token1 = await pipeAsync( makeACall, parseAuthenticatedUser )(x, y); console.log(token1); // throws at syncUserWithCore const token2 = await pipeAsync( makeACall, parseAuthenticatedUser, syncUserWithCore, makeToken )(x, y); console.log(token2); } catch (e) { console.error(e); } })(); 
Interesting Posts

Преобразование типа Spring MVC: PropertyEditor или Converter?

android-sdks / build-tools / 17.0.0 / aapt: ошибка при загрузке разделяемых библиотек: libz.so.1: невозможно открыть файл общих объектов: нет такого файла или каталога

Удалить значок центра синхронизации

Как подключить Western Digital «Мой паспорт» с помощью других средств?

Потенциальное загрязнение кучи по параметру varargs

Как ValueTypes происходят из Object (ReferenceType) и все еще являются ValueTypes?

WPF MVVM Зачем использовать ContentControl + DataTemplate Views, а не прямые XAML Window Views?

Проверка на стороне сервера с помощью CXF Webservice

Отобразить jquery ui автозаполненный список событий фокуса

Чтение файла Excel непосредственно из сценария R

неверная последовательность байтов для кодирования “UTF8”

Как очистить текущее состояние «только для чтения» на USB-накопителе, которое я установил с помощью Rufus?

Android EditText, мягкая клавиатура показать / скрыть событие?

Программа запускается и появляется в диспетчере задач, но затем выделяет половину моего процессора и сбои

Любой способ использования специального инструмента сравнения с cleartool / clearcase?

Давайте будем гением компьютера.