Js Deferred/Promise/Future по сравнению с функциональными языками, такими как Scala

Я в основном использую языки программирования, такие как Scala и JavaScript. Я пытаюсь понять сходства и различия в том, как асинхронное реактивное программирование используется на обоих языках. Вы можете мне помочь?

Я не принимаю какие-либо конкретные Js Promise Framework, потому что, кажется, многие реализуют аналогичные спецификации (например, Promise/A). Я только использовал Q до сих пор.


Кажется, что в Javascript мы называем Deferred объект, который мы решили завершить Promise, В Scala, кажется, Promise это объект, который вы решили получить Future монада.

Может кто-нибудь сказать мне, если это правильно? Есть ли веская причина для другого использования термина Promise между Джи и Скалой?


Кроме того, в Скала мы обычно цепочки Future монады с дальнейшими вычислениями с использованием таких операторов, как map а также flatMap (также называемый bindв Хаскеле). Что является эквивалентом этого в Js?

Я могу ошибаться, но мне кажется, что в Js then на Promise вид ручки как map а также flatMap операторы верно? Если это так, возможно ли получить promise of promise of result в Js? Как мы можем получить Future[Future[Result]] в Scala (который может быть сведен к Future[Result] тем не мение).


Это Js Promise монада? Это выглядит так, даже если имена методов не совпадают с теми, которые мы встречаем в литературе по монадам.

3 ответа

Решение

И да и нет.

Пока крайне похоже. С обещаниями JavaScript, соответствующими спецификации Promises/A+ .then на самом деле не монадическая привязка и делает .map а также .flatMap и то и другое. Внутри .then Обработчик, когда вы вернете обещание, он будет рекурсивно развернут.

Promise.delay(1000).then(function() {
    return Promise.delay(1000).then(function () {
        return Promise.delay(2000);
    }).then(function () {
        return Promise.delay(5000)
    });
}).then(function () {
    alert("This is only shown after 8 seconds and not one");
});

(скрипка)

Вы правы, что стандартные библиотеки обещаний JS и спецификация A + не содержат монадических обещаний. Они были обсуждены, и реализации как обещания фантазии существуют. Они следуют отличающимся спецификациям и имеют небольшое принятие. Также посмотрите это. Об этом продолжалось обсуждение на форуме по языковой разработке - esdiscuss и monadic. .chain метод, который не отображает и допускает монадические обещания, рассматривается, но вряд ли удастся это сделать.

Это по прагматическим причинам. Нынешний способ выполнения обещаний чрезвычайно полезен. Редкие случаи, когда вы действительно хотите Future[Future и обычно вы хотите, чтобы продолжения просто работали на языке. Обещания "заимствуют" у монад и в некотором смысле являются "монадическими". .then очень близко, чтобы связать, и в моей голове я использую их взаимозаменяемо:)

Невозможно иметь Promise[Promise[Value]] как Future[Future[Value]] в Scala с большинством многообещающих библиотек. Вы должны были бы обернуть это в объект и иметь Promise[Container[Promise[Value]]],

Promise.delay(1000).then(function () {
    return Promise.delay(1000).then(function () {
        return {
            wrap: Promise.delay(2000).then(function () {
                return Promise.delay(5000);
            })
        };
    });
}).then(function () {
    alert("This logs after 1 second");
    // I've also not seen a really solid use case 
    // except TypeScript type inference which is meh
});

(скрипка)

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

Похоже, что в Javascript мы называем Deferred объект, который решаем, чтобы завершить Обещание. В Scala кажется, что Promise - это объект, который вы решаете получить в будущем.

Может кто-нибудь сказать мне, если это правильно? Есть ли веская причина для> разного использования термина Promise между Js и Scala?

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

val promise = Promise[String]
val future1 = promise.future
val future2 = future1.map { case s => println(s); s }

future2.onSuccess { case s => println(s + " 2nd time") }

promise.success("promise completed")

Как только вы выполните последнюю инструкцию, вывод будет

promise completed
promise completed 2nd time

В Scala вы читаете значение из Future, используя onComplete, или цепуете его, используя map, и пишете в Future, используя его аналог Promise.

В спецификации JS Promise A+ они объединены, Promise.then используется как для цепочки, так и для получения значения для побочного эффекта (например, console.log), для записи вы будете использовать resolve как фрагмент кода ниже

var promise = new Promise(function(resolve, reject){
    Thread.sleep(10000);
    resolve("promise completed");
}

Я пытаюсь понять сходства и различия в том, как асинхронное реактивное программирование используется на обоих языках.

Этот документ здесь не сравнивает обещания Javascript со Scala, но вместо этого обещания Javascript с C++ C# и Python: https://github.com/KjellSchubert/promise-future-task. Я знаю, что это не совсем то, о чем вы просили, но, тем не менее, это может дать вам несколько интересных советов.

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

См, например, cpsfyбиблиотека.

Кроме того, есть структурная разница из-за .then принимает 2 функции, в то время как .chainпринимает только один. Однакоchain принятие 2 или даже любого количества функций аргумента может быть реализовано, например, с CPS обертка от cpsfy:

//function returning CPS function with 2 callbacks
const readFileCps = file => (onRes, onErr) =>  
  require('fs').readFile(file, (err, content) => {
    err ? onErr(err) : onRes(content)
  })

// CPS wraps a CPS function to provide the API methods
const getLines = CPS(readFileCps('name.txt'))
  // map applies function to the file content
  .map(file => file.trim()) 
  .filter(file => file.length > 0)
  // chain applies function that returns CPS function
  .chain(file => readFileCps(file))
  .map(text => text.split('\n'))
// => CPS function with 2 callbacks

// To use, simply pass callbacks in the same order
getLines(
  lines => console.log(lines),  // onRes callback
  err => console.error(err)  // onErr callback
)
Другие вопросы по тегам