lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Tue, 19 Sep 2023 10:24:07 +0100
Marcus Mason <m4gicks@gmail.com> wrote:

> >Use case is implementing something like an effect system for Lua, see
> ><https://koka-lang.github.io/koka/doc/book.html> where causing an
> >effect is implemented by yielding in Lua.
> 
> The general pattern I think for this is to yield a tagged value  to request
> an effect be performed. You might expose a function called "perform(...)"
> which performs such a yield. You can then implement a closer in terms of
> this higher level function and it should just work: tm:

My current solution is to not use "coroutine.close" but instead do
"coroutine.resume(early_return)" to close the coroutine. In this
context, "early_return" is a special marker that causes a "perform"
function, which you mentioned, to initiate a stack unwinding by invoking
"error(early_return)".

local function catch_early_return(...)
  if ... == early_return then
    error(early_return)
  else
    return ...
  end
end

function perform(...)
  return catch_early_return(coroutine.yield(...))
end

See also attached "cantyield2.lua" file, which solves the issue (but
requires resuming the coroutine during the cleanup process, as Gé
Weijers already suggested).

So instead of calling "coroutine.close", I do a
"coroutine.resume(early_return)".

Inside the coroutine, I use an "xpcall" to ensure that the coroutine's
stack is unwound on errors (including the "early return" error), such
that all __close metamethods run without needing to use
"coroutine.close".

A tricky issue is to keep track of all involved call stacks for
debugging purposes (including nested coroutines), which is what I'm
still working on.

Regards,
Jan

Attachment: cantyield2.lua
Description: Binary data