<commit_before>export const backtracker = (spec, stack=[[spec.root]]) => ({
  current() {
    return stack[0][0];
  },
  result() {
    return spec.extract(stack[0][0]);
  },
  skip() {
    const k = stack.findIndex(a => a.length >= 2);
    if (k >= 0)
      return backtracker(spec, [stack[k].slice(1)].concat(stack.slice(k + 1)));
  },
  step() {
    const todo = spec.children(stack[0][0]) || [];
    return todo.length ? backtracker(spec, [todo].concat(stack)) : this.skip();
  }
});


export function* results(gen, pred) {
  let g = gen;

  while (g) {
    if (!pred || pred(g.current())) {
      const val = g.result();
      g = g.step();
      if (val != null)
        yield val;
    } else
      g = g.skip();
  }
};


export const empty = () => backtracker({
  root    : null,
  extract : () => {},
  children: () => {}
});


export const singleton = x => backtracker({
  root    : x,
  extract : x => x,
  children: () => {}
});


if (require.main == module) {
  const n = parseInt(process.argv[2]) || 4;

  const gen = backtracker({
    root: {
      xs: [],
      sz: 0,
      mx: 1
    },
    extract(node) {
      if (node.sz == n)
        return node.xs;
    },
    children(node) {
      const ch = [];

      for (let i = node.mx; i < n - node.sz + 1; ++i)
        ch.push({
          xs: node.xs.concat(i),
          sz: node.sz + i,
          mx: Math.max(node.mx, i)
        });

      return ch;
    }
  });

  const out = [];
  for (const a of results(gen))
    out.push(a);

  console.log(JSON.stringify(out));
}<commit_msg>generators: minor cleanup<commit_after>export const backtracker = (spec, stack=[[spec.root]]) => ({
  current() {
    return stack[0][0];
  },
  result() {
    return spec.extract(stack[0][0]);
  },
  skip() {
    const k = stack.findIndex(a => a.length >= 2);
    if (k >= 0)
      return backtracker(spec, [stack[k].slice(1)].concat(stack.slice(k + 1)));
  },
  step() {
    const todo = spec.children(stack[0][0]) || [];
    return todo.length ? backtracker(spec, [todo].concat(stack)) : this.skip();
  }
});


export function* results(gen, pred) {
  let g = gen;

  while (g) {
    if (!pred || pred(g.current())) {
      const val = g.result();
      g = g.step();
      if (val != null)
        yield val;
    } else
      g = g.skip();
  }
};


if (require.main == module) {
  const n = parseInt(process.argv[2]) || 4;

  const gen = backtracker({
    root: {
      xs: [],
      sz: 0,
      mx: 1
    },
    extract(node) {
      if (node.sz == n)
        return node.xs;
    },
    children(node) {
      const ch = [];

      for (let i = node.mx; i < n - node.sz + 1; ++i)
        ch.push({
          xs: node.xs.concat(i),
          sz: node.sz + i,
          mx: Math.max(node.mx, i)
        });

      return ch;
    }
  });

  for (const a of results(gen))
    console.log(`${a}`);
}
{'fraction_non_alphanumeric': 0.20056199508254302, 'fraction_numerical': 0.01053740779768177, 'mean_word_length': 2.059076262083781, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1274928', 'n_tokens_mistral': 1066, 'n_tokens_neox': 1031, 'n_words': 242}