Ленивое декартово произведение массивов (произвольные вложенные циклы)

Есть другие вопросы по этому поводув Другие языки, и другиене-ленивым Версии JavaScript, но никаких ленивых версий JavaScript, которые я нашел.

Дан массив произвольного числа массивов произвольного размера:

var sets = [ [2,3,4,5], ['sweet','ugly'], ['cats','dogs','hogs'] ];

и функция обратного вызова:

function holla( n, adj, noun ){
  console.log( [n,adj,noun].join(' ') );
}

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

lazyProduct( sets, holla );
// 2 sweet cats
// 2 sweet dogs
// 2 sweet hogs
// 2 ugly cats
// 2 ugly dogs
// 2 ugly hogs
// 3 sweet cats
// 3 sweet dogs
// 3 sweet hogs
// 3 ugly cats
// 3 ugly dogs
// 3 ugly hogs
// 4 sweet cats
// 4 sweet dogs
// 4 sweet hogs
// 4 ugly cats
// 4 ugly dogs
// 4 ugly hogs
// 5 sweet cats
// 5 sweet dogs
// 5 sweet hogs
// 5 ugly cats
// 5 ugly dogs
// 5 ugly hogs

Обратите внимание, что эти комбинации совпадают с результатами, которые вы получили бы, если бы у вас были вложенные циклы:

var counts     = [2,3,4,5];
var adjectives = ['sweet','ugly'];
var animals    = ['cats','dogs','hogs'];
for (var i=0;i<counts.length;++i){
  for (var j=0;j<adjectives.length;++j){
    for (var k=0;k<animals.length;++k){
      console.log( [ counts[i], adjectives[j], animals[k] ].join(' ') );
    }
  }
}

Преимущества декартового произведения:

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

Вы можете увидеть критерии для ответов ниже здесь:
http://jsperf.com/lazy-cartesian-product/26

Ответы на вопрос(4)

Ваш ответ на вопрос