Эмулировать / использовать продолжения в JavaScript? - PullRequest
4 голосов
/ 11 декабря 2011

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

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 ]

3 голосов
/ 11 декабря 2011

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
2 голосов
/ 11 декабря 2011

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

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?У меня может быть неправильный алгоритм для этого, но вы понимаете, что я предлагаю запомнить состояние функции между вызовами.

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

1 голос
/ 14 декабря 2011

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

1 голос
/ 11 декабря 2011

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

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;   
}

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

...