Generator function support?

interop

#1

Is there support for generator functions? i.e. function*() {}

I’m writing a binding for a js library that has a generators API.

I tried searching around and didn’t find anything, although it doesn’t help that the word “generator” has more than one meaning!


#2

Here is an example for the consumption of a generator:

module Gen = {
  type jsYield('v);
  type t('i, 'o, 'r);

  type yield('p, 'd) =
    | Pending('p)
    | Done('d);

  [@bs.get] external value: jsYield('v) => 'v = "";

  [@bs.get] external done_: jsYield('v) => bool = "done";

  [@bs.send] external next_: (t('i, 'o, 'r), 'i) => jsYield('o) = "next";

  let castYield: (t('i, 'o, 'r), jsYield('o)) => jsYield('r) =
    (g, y) => Obj.magic(y);

  [@bs.send] external return: (t('i, 'o, 'r), 'r) => jsYield('r) = "";

  let next = (g, i) => {
    let jsYield = next_(g, i);
    let d = done_(jsYield);
    if (d) {
      let jsYield = castYield(g, jsYield);
      Done(value(jsYield));
    } else {
      let v = value(jsYield);
      Pending(v);
    };
  };

  let rec toList = gen => {
    let n = next(gen, ());
    switch (n) {
    | Done(d) => [Done(d)]
    | Pending(p) => [Pending(p), ...toList(gen)]
    };
  };
};

let makeGenWithInput: unit => Gen.t(int, int, string) = [%raw
  "function*() {
  var a = yield 1;
  var b = yield 2 * a;
  var c = yield 3 * b;
  return 'OK';
}"
];

let makeGen: unit => Gen.t(unit, int, string) = [%raw
  "function*() {
 	yield 1;
	yield 2;
	yield 3;
	return 'OK';
}"
];

let print = v =>
  switch (v) {
  | Gen.Done(d) => "done: " ++ d
  | Pending(v) => "pending: " ++ string_of_int(v)
  };

let g = makeGenWithInput();
Js.log(Gen.(g->next(10)->print));
Js.log(Gen.(g->next(20)->print));
Js.log(Gen.(g->next(30)->print));
Js.log(Gen.(g->next(40)->print));

let g = makeGen();
let l = Gen.toList(g);
Belt.List.(map(l, print)->forEach(Js.log));

#3

Nice, thanks. Any idea if there’s a plan to introduce this approach into Belt? Possibly with syntax sugar?