//Note it's probably cheaper to pass a CapturedCont than a Continuation Trampoline stream2(Search &s, CapturedVar<int> m, Trampoline c) { CapturedLambda(Search &, int) rest; UncountedLambda(Search &, int) rest_uncounted = rest; *rest = [=](Search &s, int n) { n += 1; if (n == 4) { return s.fail(); } else { s.alt(trampoline(rest_uncounted, s, n)); // cout << "m is " << *n * *n << endl; *m = n * n; return c; } }; return trampoline(rest, s, 0); }
//oops, the return value could be nixed by stack clean exception //but it worked when I made it always throw... {}{}{} WHY DOES IT WORK? //OH it works because it doesn't use the search until AFTER it returns the value Trampoline stream1(Search &s, CapturedVar<int> m, Trampoline c) { CapturedLambda(Search &, int) rest; UncountedLambda(Search &, int) rest_uncounted = rest; *rest = [=](Search &s, int n) { n = n + 1; if (n == 10) { return s.fail(); } else { s.alt(trampoline(rest_uncounted, s, n)); *m = n; // cout << "n is " << *n << endl; return c; } }; cout << rest.get()->use_count() << endl; return trampoline(rest, s, 0); }
Trampoline AmbTest(Search &s) { CapturedVar<int> n, m; CapturedCont c1, c2, c3; UncountedCont c1_u = c1, c2_u = c2, c3_u = c3; combine_refs(c1, c2, c3); //note it can't safely use Search inside of functions that return a value *c1 = [=](Search &s) { return stream1(s, n, trampoline(c2_u, s)); }; *c2 = [=](Search &s) { return stream2(s, m, trampoline(c3_u, s)); }; *c3 = [=](Search &s) { if (*n != *m) return s.fail(); else { s.results.insert_or_assign("n", *n); s.results.insert_or_assign("m", *m); return end_search; } }; cout << c1.get()->use_count() << endl; cout << c2.get()->use_count() << endl; cout << c3.get()->use_count() << endl; return trampoline(c1, s); }