https://github.com/micropython/micropyt ... t-65945634 . I didn't continue it at that time, because the concepts are not exactly well-known and familiar, and while intuitively "it should work", the intuition may be wrong or missing some details, and the devil is in these details.
So, to clarify again, the talk is NOT about saving C stack and stuff. That way is obviously not scalable for embedded usage. The talk is about switching precisely calculated value stacks of Python functions.
As initial data, there's
Code: Select all
wifi.scan(callback)
What we'd like to achieve is to transform it into following usage, preferrably with native C means:
Code: Select all
for i in wifi.iterscan():
print(i)
General intuitive idea to achieve that is to have "wifi.scan(lambda v: (yield v))". Well, that intuitive idea is immediately wrong, because in Python, a function with yield is a generator function, calling it produces generator. So, callback above will just produce void instances of generators. Even if that wasn't the case, Python allows to yield only from generator itself, not from any functions a generator calls (in particular, not from callback function).
Well, instead of using yield statement, let's use .send() function. Common sense interpretation of coroutine theory says that "yield v" is equivalent to "caller.send(v)". There're however more questions like which generator to send to. And thinking about it, it's only in formal theory yield and .send equivalent, with asymmetric Python coroutines, yield is like return and send is like call, and supporting iteration, generator should "return" values, not try to start another iteration of upstream receiver.
So, multiple deadends. Let's simplify task to convert just following simple Python function:
Code: Select all
def f(cb):
i = 0
while 1:
cb(i)
i += 1
Code: Select all
function f(n, cb)
for i = 1, n do
cb(i)
end
end
f(10, function (i) print(i) end)
function iter_f(n)
return coroutine.wrap(function ()
f(n, coroutine.yield)
end)
end
for a in iter_f(5) do
print(a)
end