Эмулировать / использовать продолжения в JavaScript?


У меня есть функция, которая вычисляет произведение чисел в массиве. Функция должна работать следующим образом

function prod (array){
//compute and return product
}

var arr = [1,2,3,0,4,5,0,6,7,8,0,9];

the function call:
prod(arr); //should return 6
prod(arr); //should return 20
prod(arr); //should return 336 (6*7*8)
prod(arr); //should return 9
prod(arr); //should return 0
prod(arr); //should return 0
prod(arr); //should return 0

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

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

JavaScript-хорошо разработанный язык, поэтому я надеюсь, что там должно быть что-то, что может подражать этому. Если в JS нет ничего, что могло бы это сделать, я не возражаю закончить неудачей и двигаться дальше. Так что, не стесняйтесь сказать, что это невозможно.

Спасибо.

4 4

4 ответа:

JavaScript не способен поддерживать продолжения: ему не хватает хвостовых вызовов.

Обычно я бы написал это, чтобы использовать" очередь " видов, хотя CPS также может (просто иметь конечный стек : -) обратите внимание, что другое состояние также может быть захвачено в закрытии, что делает его "явным продолжением" видов ... в очень грубом смысле.

Пример использования замыкания и очереди:

function prodFactory (array){
   // dupe array first if needed, is mutated below.
   // function parameters are always locally scoped.
   array.unshift(undefined)  // so array.shift can be at start
   // also, perhaps more closured state
   var otherState
   // just return the real function, yippee!
   return function prod () {
      array.shift()
      // do stuff ... e.g. loop array.shift() and multiply
      // set otherState ... eat an apple or a cookie
      return stuff
   }
}

var prod = prodFactory([1,2,3,0,4,5,0,6,7,8,0,9])

        // array at "do stuff", at least until "do stuff" does more stuff
prod()  // [1,2,3,0,4,5,0,6,7,8,0,9]
prod()  // [2,3,0,4,5,0,6,7,8,0,9]
prod()  // [3,0,4,5,0,6,7,8,0,9]

Счастливое кодирование.


"законченная реализация". Хотя это конкретная проблема можно избежать мутации массива и просто использовать индекс: применяются те же понятия. (Ну, немного по-другому. С помощью только индекса закрытая переменная будет изменена, тогда как при таком подходе объект мутирует.)

function prodFactory (array) {
   array = array.slice(0)
   return function prod () {
      var p = 1
      for (var n = array.shift(); n; n = array.shift()) {
        p *= n
      }
      return p
   }
}

var prod = prodFactory([1,2,3,0,4,5,0,6,7,8,0,9])

prod()  // 6
prod()  // 20
prod()  // 336

Вы можете дать функции свойство, которое будет запоминаться между вызовами:

function prod (array){
   if (typeof prod.index === "undefined" || prod.currentArray != array) {
      prod.currentArray = array;
      prod.index = 0;
   }

   if (prod.index >= array.length)
      return 0;

   //compute and return product
   var p = 1,
       c;
   while (prod.index < array.length) {
      c = array[prod.index++];
      if (c === 0)
         return p;
      p *= c;
   }
   return p;
}

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

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

Вы можете попробовать что-то вроде

var index = 0;
function prod (array){
    if(index < array.length){
    var prod=1;
    for(int i=index;i<array.length;i++){
        if(array[i] != 0){
            prod = prod * array[i];
        }
        else{
            index = i+1;
            return prod;
        }
    }
}
return 0;   
}

Это будет обновлять Индекс глобальной переменной каждый раз, когда вызывается функция.

То, что вы ищете здесь, - это генераторы . Начиная с 1.7, JavaScript поддерживает их .