# Cannot catch continuation through findall/3

**URL:** <https://swi-prolog.discourse.group/t/cannot-catch-continuation-through-findall-3/7043>\
**Category:** Help!\
**Created:** [December 7, 2023, 7:11pm UTC](https://swi-prolog.discourse.group/t/cannot-catch-continuation-through-findall-3/7043 "2023-12-07T19:11:43Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![z5h](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/z5h/32/5445_2.png) [@z5h](https://swi-prolog.discourse.group/u/z5h)\
**Post date:** [December 7, 2023, 7:11pm UTC](https://swi-prolog.discourse.group/t/cannot-catch-continuation-through-findall-3/7043/1 "2023-12-07T19:11:43Z")

</div>

I’m using DCGs for implicit state management for a game.  
I’m also using delimited continuations to implement a Monte Carlo Tree Search version of the amb operator (call it mc\_amb for short).  
There is a proof of concept here ["Monte-Carlo amb" in Prolog, proof of concept · GitHub](https://gist.github.com/z5h/f43f2bd6987e99e242aecfb08683bc23)

amb is an operator (useful in other languages) where we capture the current continuation, and try selecting a member of a list until our continuation doesn’t fail. (This is not particularly useful in Prolog where we get this for free.)

The idea of mc\_amb, is we want to select a member of a list, and run the continuations for each selection. Assuming the continuations contain randomness (like in a game), we replay each to get statistical info on the “utility” of our selection, and find a suitable selection.

This all works.

To apply this to a DCG rule, I first do

```prolog
all_outcomes(Rule) -->
    state(S0, States),
    { findall(S1, phrase(Rule, [S0], [S1]), States) }.

```

So that I have a list I can select from in my `mc_amb`, find the best one, and continue on.

However, I get:  
`Cannot catch continuation through findall/3`.

Is there a way to do what I want to do without the above problem?

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [December 8, 2023, 8:45am UTC](https://swi-prolog.discourse.group/t/cannot-catch-continuation-through-findall-3/7043/2 "2023-12-08T08:45:25Z")

</div>

You have to remember that a continuation does **not** capture the choice points. That, if I recall correctly, is one of the reasons why it doesn’t work well with e.g., findall/3. You have to make sure that both the reset/3 and shift/1 are inside the goal of the findall/3.

The problem is not entirely clear to me. As you suggest though, it seems Prolog doesn’t need continuations to solve this problem. If this is the case, I’d avoid them. They are relatively slow and indeed do not add much to Prolog. The motivating _coroutining_ examples can all be implemented with other means that are more efficient. The reason for adding them to SWI-Prolog is that they allow for a fairly simple and still fairly efficient implementation of _tabling_. The limitations imposed by continuations are already limitations of tabling anyway. Otherwise, _engines_ seem to be a cleaner way to implement coroutines.

---

<div class="post-metadata">

**Author:** ![z5h](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/z5h/32/5445_2.png) [@z5h](https://swi-prolog.discourse.group/u/z5h)\
**Post date:** [December 8, 2023, 4:52pm UTC](https://swi-prolog.discourse.group/t/cannot-catch-continuation-through-findall-3/7043/3 "2023-12-08T16:52:31Z")

</div>

In essence I need “select\_once with agency”, where this “smart select” knows that the continuation post-selection, contains calls to random. And so this “smart select” can run simulations on the continuation to see what likelyhood of success its selections might have.

In any case. I think I can keep my findall outside of the reset.

---

<div class="post-metadata">

**Author:** ![z5h](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/z5h/32/5445_2.png) [@z5h](https://swi-prolog.discourse.group/u/z5h)\
**Post date:** [December 8, 2023, 5:19pm UTC](https://swi-prolog.discourse.group/t/cannot-catch-continuation-through-findall-3/7043/4 "2023-12-08T17:19:49Z")

</div>

Are there particularly slow parts in delimited continuations?

---

<div class="post-metadata">

**Author:** ![kuniaki.mukai](https://avatars.discourse-cdn.com/v4/letter/k/c67d28/32.png) [@kuniaki.mukai](https://swi-prolog.discourse.group/u/kuniaki.mukai)\
**Post date:** [December 9, 2023, 5:16am UTC](https://swi-prolog.discourse.group/t/cannot-catch-continuation-through-findall-3/7043/7 "2023-12-09T05:16:44Z")

</div>

> [@jan](#):
>
> The reason for adding them to [SWI-Prolog](https://www.swi-prolog.org/pldoc/doc_for?object=manual) is that they allow for a fairly simple and still fairly efficient implementation of _tabling_

Sounds interesting because it suggests, I think, shift/reset would be useful for linear ordered ancestor resolution prover. For a long time, IMHO, tabling in general seems close to that prover. I will review old codes of mine on the prover.

On the other hand, I dropped all shift/reset from my zdd implementation, because of the existence strange 0 (not true), and shift/1 is not module transparent, which are not serious at all, but for my use of shift/reset as DCG, I lost gradually merits of shift/reset. Now I use the `b_setval` for shift/reset in stead.

I am rather interested for handling local stacks to implement such like the current shift/reset, reminding me of spaghetti-stack controls in InterLisp a long long time ago.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [December 9, 2023, 5:41pm UTC](https://swi-prolog.discourse.group/t/cannot-catch-continuation-through-findall-3/7043/10 "2023-12-09T17:41:53Z")

</div>

> [@z5h](#):
>
> Are there particularly slow parts in delimited continuations?

It is simply a quite involved process. shift/1 creates a representation of the stack frames between the shift/1 and reset/3 calls as a Prolog term. Calling this has to rebuild the stack frames from this. There might be some more room for optimization. With the implementation of tabling using this, I did most of the low-hanging fruit though.

---

<div class="post-metadata">

**Author:** ![z5h](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/z5h/32/5445_2.png) [@z5h](https://swi-prolog.discourse.group/u/z5h)\
**Post date:** [December 10, 2023, 4:45am UTC](https://swi-prolog.discourse.group/t/cannot-catch-continuation-through-findall-3/7043/11 "2023-12-10T04:45:25Z")

</div>

@anon95304481

My problem is that the goal I want to trial-run is specifically **the current continuation**.

Forgive the contrived example, but imagine representing a game this this:

```prolog
play_game -->
  init_board,
  play_moves_or_end.

play_moves_or_end -->
  play_move, !, 
  next_turn,
  play_moves_or_end.

play_moves_or_end -->
  end_game.

```

Some players play randomly. Game flow is declarative, so to randomize a move can I do:

```prolog
all_outcomes(Rule) -->
    state(S0, States),
    { findall(S1, phrase(Rule, [S0], [S1]), States) }.

random_outcome(Rule) -->
    all_outcomes(Rule),
    state(Outcomes, Chosen),
    { random_member(Chosen, Outcomes) }.

```

Great, now I can have players that play randomly.

If I want a player with a (Monte Carlo Tree Search) strategy, then the Goal I want to trial is “the rest of the game from this point”, I.e., the current continuation, with the possible move selections generated with findall.

Maybe there’s some CPS transform I can do to always have the continuation on hand.

---

<div class="post-metadata">

**Author:** ![z5h](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/z5h/32/5445_2.png) [@z5h](https://swi-prolog.discourse.group/u/z5h)\
**Post date:** [December 10, 2023, 6:28am UTC](https://swi-prolog.discourse.group/t/cannot-catch-continuation-through-findall-3/7043/12 "2023-12-10T06:28:35Z")

</div>

Just found this relatively new implementation of delimited control in Prolog, which maintains choice points. [https://www.researchgate.net/publication/369963285\_Disjunctive\_Delimited\_Control](https://www.researchgate.net/publication/369963285_Disjunctive_Delimited_Control)

---

<div class="post-metadata">

**Author:** ![z5h](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/z5h/32/5445_2.png) [@z5h](https://swi-prolog.discourse.group/u/z5h)\
**Post date:** [December 10, 2023, 4:35pm UTC](https://swi-prolog.discourse.group/t/cannot-catch-continuation-through-findall-3/7043/15 "2023-12-10T16:35:52Z")

</div>

> [@anon95304481](#):
>
> I doubt that it is the current continuation

You are correct. My terminology was off. I was trying to emphasize that the “goal” I was interested was the delimited continuation I (currently) had at hand. And not a term I could easily construct because program flow is implicit in my DCG and not explicitly handled.

> [@anon95304481](#):
>
> Do you have a working game computation Prolog code somewhere?

Yes, but, not the way I want to represent things.

I have older code with explicit state handling, where a game must implement:  
`possible_moves(State, Moves)`  
`apply_move(State, Move, NextState)`

The “engine” that runs these games uses Monte Carlo Tree Search for all players.

This all works and I’ve coded a few games this way. But my code with explicit state management is tedious.  
So I’, trying to express game state transitions with DCG syntax for state management. Still working on the best way to express things, but I can do things like:

```prolog
euchre_rounds_until_win -->
    req(p1p3_score:Score1),
    req(p2p4_score:Score2),
    try((
        { Score1 < 10, Score2 < 10 },
        euchre_round,
        next_dealer,
        euchre_rounds_until_win
    )).

```

(`req` looks up an assoc K:V from current state, `try` attempts something and commits, otherwise succeeds).

Now, any time a player’s legal moves is dictated by some rule `Rule`, I could simply invoke `Rule` and this would allow me to enumerate all possible games.  
Instead, I’d like to “wrap” the rules with `strategize` like so

```prolog
strategize(Rule) -->
    req(turn:Player),
    req((Player:strategy):Strategy),
    {Term =.. [Strategy, Rule]},
    Term.

```

I showed the random strategy above (find all outcomes of a rule and select a random member). The Monte Carlo strategy would/might use delimited continuations and the amb trick to perform the Monte Carlo analysis.

> [@anon95304481](#):
>
> I find the idea of doing game computation with sampling quite appealing. Although for practical purposes, one can possibly only take very few samples, otherwise the game computation is bugged down by the exponential explosion.

I find it quite appealing too. Specifically, the “dumber” the sampling is, the easier it is to make it fast and parallelizable. I already have code playing some small strategic games better than me, and solving some game-puzzles that I didn’t expect would be solvable this way (because so much of the game-tree would be left unexplored).

In any case, my “problem” isn’t one of “how can I make Prolog do this thing”.

It’s, specifically:  
With what Prolog features, DSLs, syntax can I most declaratively state game rules and transitions, AND have opponents play the game with different strategies (including a strategies that can make use of said rules/transitions to play hypothetical simulation games).
