Понимание продолжений в JavaScript

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

Это упражнение:

Определите функцию с именем bothC, аналогичную seqC, которая принимает функции fC и gC и выполняет успешное или неудачное продолжение. Обе функции fC и gC принимают успешное и неудачное продолжение. Ваша функция bothC должна вызывать как fC, так и gC, несмотря ни на что, но вызывать только успех, если оба успешно завершились, и неудачу в противном случае. Не забывайте, ваша функция никогда не вернется!

Кажется, это верный ответ:

var bothC = function (fC, gC, success, failure) {
    fC(
      function() {
        gC(success, failure);  
      },
      function() {
        gC(failure, failure);    
      }
    );
};

Но почему я не могу просто сделать это?

var bothC = function(fC, gC, success, failure) {
  fC(gC(success, failure), gC(failure, failure));
}

person helpermethod    schedule 08.08.2011    source источник
comment
Интересно, нужно прочитать учебник сейчас ...   -  person Mrchief    schedule 08.08.2011


Ответы (3)


Каждый раз, когда у вас есть функция, за которой следуют скобки вокруг набора аргументов (даже если аргументов нет, это все еще набор аргументов), сообщение для JS будет execute immediately. Это означает, что gC(success, failure) фактически запускает gC, а затем возвращает все, что должно вернуть gC. fC(gC(success, failure), gC(failure, failure)); в основном означает "вызов fC с возвратом gC(success, failure) и gC(failure, failure) в качестве параметров"

Чтобы предотвратить это действие и по-прежнему сделать его вызываемым, вам нужно обернуть его в function(){} (он может быть анонимным или нет). Это превратит его в возвращаемый и вызываемый объект, а не просто как вызов метода. fC(function() {gC(success, failure); }, function() { gC(failure, failure); } ); означает «вызов fC с функцией, которая будет вызывать gC(success, failure), и функцией, которая будет вызывать gC(failure, failure) в качестве параметров»


Как и к вашему сведению, Суссман и Стил показали, что продолжения и замыкания, более или менее, - это одно и то же, разница в основном в синтаксисе (это было в конце 70-х. Прочтите Габриэль / Стил История Lisp стр. 33). JS имеет отличный синтаксис замыкания, но, на мой взгляд, лучшим примером продолжения в популярном в настоящее время языке является синтаксис Python yield. Просто говорю.

person cwallenpoole    schedule 08.08.2011
comment
Не согласен с тем, что у Python лучший синтаксис. Если у вас есть оператор yield в функции Python, вы не можете выполнить рефакторинг для вызова других функций (отложив вызов до yield). Как только у вас есть yield, эта функция специально помечается как генератор. Это важно, если вы хотите поддерживать систему, основанную на продолжениях (я написал симулятор и действительно хотел преобразовать свои операторы yield в две разные функции). Я бы хотел увидеть что-нибудь с синтаксисом Python, принявшее что-то столь же мощное, как call / cc. Конечно, есть над чем подумать при сравнении с синтаксисом JS. - person ccoakley; 08.08.2011
comment
@ccoakley Что ж, мне это нравится, потому что это самый яркий пример реального продолжения - возвращение функции как чего-то, что может продолжаться позже, в отличие от закрытия, которое возвращает вызываемый объект. - person cwallenpoole; 09.08.2011
comment
Да, тут не могу не согласиться. Вы также позволили себе показать лучший пример ... на современном популярном языке. Но то, что никто не делает это лучше, не означает, что мне это должно нравиться! К тому же я привык к синтаксису javascript :) - person ccoakley; 09.08.2011
comment
Вздох ... Да ... слишком часто у нас возникают такие проблемы стандартов ... Однажды, будет построен самый красивый язык, который, как мы все можем согласиться, прекрасен. (К сожалению, этот день прошел и предшествовал современному компьютеру) - person cwallenpoole; 09.08.2011

Потому что он вызывает gC (вместо того, чтобы откладывать его) и передает свой результат fC.

person Daniel A. White    schedule 08.08.2011

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

person Ned Batchelder    schedule 08.08.2011