⚠️ Warning: This is a draft ⚠️
This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.
If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.
Here is a simplistic coroutine implementation for [[../#J|J]].
Note that this version does not support switching between coroutine contexts -- that would have been an unnecessary complication for this task. (So, technically, it might be better to call this "coroutine inspired".)
NB. u coroutine y NB. execute u in new coroutine context
coroutine=: 1 :0
stack=. ''
verb=. u
noun=. y
while. do. context=. verb noun
select. (0 {:: context) * 1+*#stack
case. 0 do. NB. yield
stack=. stack, 1 { context
verb=. (2 { context)`:0
noun=. 3 {:: context
case. 1 do. NB. return (with empty stack)
1 {:: context return.
case. 2 do. NB. return (with work remaining on stack)
verb=. ({: stack)`:0
noun=. 1 {:: context
stack=. }: stack
case. do. NB. (default)
invalid coroutine 1 :'error.'
end.
end.
)
NB. u yield v y return. NB. 0 -- deferred result, will be executing: u v y
yield=: 2 :0
0; u ` v,< y
)
NB. return y return. NB. 1 -- immediate result: y
return=: 3 :0
1; y
)
The philosophy here, is: A noun represents code which has already been executed (it's the result of that code having been executed). A verb represents code which has not yet been executed.
A coroutine verb must return a result built by one of the two helper verbs return
or yield
. If yield
is used, it must be supplied with two verbs and a noun. The coroutine context will stack u (the left verb) for later execution and it's argument will be the result of whatever verb was most recently executed by the coroutine context. Meanwhile the coroutine context will execute v (the right verb) right away and its argument will be the noun which was supplied to yield. Both u and v must be coroutine verbs (so they also must must provide a result prepared by return
or yield
).