<p>There is a feature called <code>resume</code> in these languages/articles, which can re-enter the position of <code>perform</code> during catch.</p>
<ul>
<li><a href="https://overreacted.io/algebraic-effects-for-the-rest-of-us/" rel="noreferrer">https://overreacted.io/algebraic-effects-for-the-rest-of-us/</a></li>
<li><a href="https://effekt-lang.org/" rel="noreferrer">https://effekt-lang.org/</a></li>
</ul>
<p>I would like to know how this feature is implemented.</p>
<p>Basically, can it be implemented in the tree walker interpreter.</p>
<p>If not, what additional work is required, such as whether to do cps transformation for all the codes of all my functions</p>
<p><sub>A little extra requirement, I am going to use this mechanism to implement exceptions, so I hope not to implement it based on exceptions</sub></p>

<exceptions><effect-systems>
How to implement resume
CC BY-SA 4.0
2023-06-07T21:38:40.213Z
Lots of papers about this won't be related to effects, but rather a mechanism for achieving abstraction of control. In particular, you can find papers about direct implementations of shift/reset. However, there's many ways to go about it and many assumptions that must be made in each case; direct (mark and copy segments of stack and jump to return addresses, coordinated with wrapper functions following a protocol about how they return places), embedding into multi-prompt delimited continuation monad, CPS interpreter, selective CPS, call/cc and a reference cell, fibers (segmented stacks), etc.
Colin James
<p>It can.</p>
<p>To implement it in the tree walker each time you encounter a <code>perform</code> you would store a pointer to the node of perform that hypothetically could be resumed. For this your nodes should be able to go up your tree. I will continue my explanation with placeholder C code.</p>
<pre class="lang-c prettyprint-override"><code>// An AST node that can go up the tree is important for the ability to skip back to and from `perform`
typedef AstNode* JumpPos;

//
struct Perform {
  JumpPos resumable;
  Frame stack;
  Object* info;
  // ...
};

Perform* init_perform(JumpPos pos, Object* info, Frame stack) {
  Perform* p = malloc(sizeof(Perform));
  p-&gt;resumable = pos;
  p-&gt;info = info;
  p-&gt;stack = stack;
  return p;
}

Perform* perform_point = NULL;
</code></pre>
<p>When you encounter <code>try</code> you would store available effect types in a stack with where to go to.</p>
<pre class="lang-c prettyprint-override"><code>struct Try {
  size_t handles_len;
  With* handles;
};

// Assuming you will match by effect type
struct With {
  EffectType type_handled;
  JumpPos position;
};

Try* tries = NULL; // you would initialise this at runtime as a dynamically resizable stack

Try try_pop(); // to pop of a Try of the stack
</code></pre>
<p>Now for the exciting part, let's say you encountered a <code>perform</code> or <code>resume</code>. You should <em>very</em> roughly do what is entailed here.</p>
<pre class="lang-c prettyprint-override"><code>// ...
case Node_Perform:
  Object* obj = parse_object(); // this is parser dependent so I left it to you
  perform_point = init_perform(current_node, obj, save_stack_frame());
  EffectType ty = type_of_object(obj);
  Try t = try_pop();
  // You should check for nulls in here but I won't for the sake of brevity

  // You could and should use a non-resizable map for this but I can't bother to implement it now
  for (size_t i = 0; i &lt; t.handles_len; i++) {
    if (effect_type_equals(t.handles[i].type_handled, Ty)) {
      jump_to(t.handles[i].position);
    }
  }
  break;
case Node_Resume:
  // Parse and check condition if true:

  if (perform_point == NULL) {
    // Error out because you resumed without performing beforehand
  }
  current_node = perform_point-&gt;resumable;
  next_expr(&amp;current_node);
  use_stack_frame(perform_point-&gt;stack);
  free_object(perform_point-&gt;info);
  free(perform_point);
  perform_point = NULL;
  break;
// ...
</code></pre>
<blockquote>
<p>Please note that as I'm writing this from my phone without my computer near me to test it you probably shouldn't copy paste this and work off of it. Instead use it as a baseline to understand the intent.</p>
</blockquote>

CC BY-SA 4.0
2023-06-18T15:48:59.300Z
2023-06-18T17:42:23.757Z
2023-06-18T17:42:23.757Z
kaiserthe13th
# How to implement resume
Posted by: username_0 on 2023-06-06
There is a feature called `resume` in these languages/articles, which can re-enter the position of `perform` during catch.

* <https://overreacted.io/algebraic-effects-for-the-rest-of-us/>
* <https://effekt-lang.org/>

I would like to know how this feature is implemented.

Basically, can it be implemented in the tree walker interpreter.

If not, what additional work is required, such as whether to do cps transformation for all the codes of all my functions

A little extra requirement, I am going to use this mechanism to implement exceptions, so I hope not to implement it based on exceptions
**Tags:** exceptions effect-systems
> **Comments:**
> **username_1**: Lots of papers about this won't be related to effects, but rather a mechanism for achieving abstraction of control. In particular, you can find papers about direct implementations of shift/reset. However, there's many ways to go about it and many assumptions that must be made in each case; direct (mark and copy segments of stack and jump to return addresses, coordinated with wrapper functions following a protocol about how they return places), embedding into multi-prompt delimited continuation monad, CPS interpreter, selective CPS, call/cc and a reference cell, fibers (segmented stacks), etc.  
---
## 1 answers
### Answer by username_2 on 2023-06-18. Score: 5
It can.
To implement it in the tree walker each time you encounter a perform you would store a pointer to the node of perform that hypothetically could be resumed. For this your nodes should be able to go up your tree. I will continue my explanation with placeholder C code.
// An AST node that can go up the tree is important for the ability to skip back to and from `perform`
typedef AstNode* JumpPos;

//
struct Perform {
  JumpPos resumable;
  Frame stack;
  Object* info;
  // ...
};

Perform* init_perform(JumpPos pos, Object* info, Frame stack) {
  Perform* p = malloc(sizeof(Perform));
  p->resumable = pos;
  p->info = info;
  p->stack = stack;
  return p;
}

Perform* perform_point = NULL;

When you encounter try you would store available effect types in a stack with where to go to.
struct Try {
  size_t handles_len;
  With* handles;
};

// Assuming you will match by effect type
struct With {
  EffectType type_handled;
  JumpPos position;
};

Try* tries = NULL; // you would initialise this at runtime as a dynamically resizable stack

Try try_pop(); // to pop of a Try of the stack

Now for the exciting part, let's say you encountered a perform or resume. You should very roughly do what is entailed here.
// ...
case Node_Perform:
  Object* obj = parse_object(); // this is parser dependent so I left it to you
  perform_point = init_perform(current_node, obj, save_stack_frame());
  EffectType ty = type_of_object(obj);
  Try t = try_pop();
  // You should check for nulls in here but I won't for the sake of brevity

  // You could and should use a non-resizable map for this but I can't bother to implement it now
  for (size_t i = 0; i < t.handles_len; i++) {
    if (effect_type_equals(t.handles[i].type_handled, Ty)) {
      jump_to(t.handles[i].position);
    }
  }
  break;
case Node_Resume:
  // Parse and check condition if true:

  if (perform_point == NULL) {
    // Error out because you resumed without performing beforehand
  }
  current_node = perform_point->resumable;
  next_expr(&current_node);
  use_stack_frame(perform_point->stack);
  free_object(perform_point->info);
  free(perform_point);
  perform_point = NULL;
  break;
// ...


Please note that as I'm writing this from my phone without my computer near me to test it you probably shouldn't copy paste this and work off of it. Instead use it as a baseline to understand the intent.
---
