Skip to content

Commit 39e0449

Browse files
committed
new implementation
1 parent 3c1985f commit 39e0449

File tree

2 files changed

+54
-79
lines changed

2 files changed

+54
-79
lines changed

src/eff.lua

Lines changed: 53 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,95 @@
11
local create = coroutine.create
2-
local resume = coroutine.resume
32
local yield = coroutine.yield
4-
local unpack0 = table.unpack or unpack
53

6-
local unpack = function(t)
7-
if t and #t > 0 then
8-
return unpack0(t)
4+
local resume = function(co, a)
5+
local st, r = coroutine.resume(co, a)
6+
7+
if not st then
8+
return error(r)
9+
else
10+
return r
911
end
1012
end
1113

12-
local inst do
13-
local cls = ("Eff: %s"):format(tostring(v):match('0x[0-f]+'))
14-
15-
inst = setmetatable({ cls = cls }, {
16-
__call = function(self)
17-
local eff = ("instance: %s"):format(tostring{}:match('0x[0-f]+'))
18-
return { eff = eff, cls = self.cls}
19-
end
20-
})
14+
local inst = function()
15+
return {}
2116
end
2217

23-
local perform = function(eff, arg)
24-
return yield { cls = eff.cls, eff = eff.eff, arg = arg }
18+
-- Call : ('arg, 'res) operation * 'arg * ('res -> 'a computation) -> 'a computation
19+
local callT = "call"
20+
local call = function(op, x, k)
21+
return { type = callT, op = op, x = x, k = k }
2522
end
2623

27-
local show_error = function(eff)
28-
return function()
29-
return ("uncaught effect `%s'"):format(eff)
30-
end
31-
end
24+
local throwT = {
25+
perform = false,
26+
resend = true
27+
}
3228

33-
local Resend do
34-
local cls = ("Resend: %s"):format(tostring(v):match('0x[0-f]+'))
29+
local perform = function(op, arg)
30+
local current = coroutine.running()
3531

36-
Resend = setmetatable({ cls = cls }, {
37-
__call = function(self, effobj, continue)
38-
return yield { eff = effobj.eff, arg = effobj.arg, continue = continue, cls = self.cls }
39-
end
40-
})
41-
end
32+
local k = function(a)
33+
return resume(current, a)
34+
end
4235

43-
local is_eff_obj = function(obj)
44-
return type(obj) == "table" and (obj.cls == inst.cls or obj.cls == Resend.cls)
36+
return yield(call(op, {arg, type = throwT.perform}, k) )
4537
end
4638

47-
local function handle_error_message(r)
48-
if type(r) == "string" and
49-
(r:match("attempt to yield from outside a coroutine")
50-
or r:match("cannot resume dead coroutine"))
51-
then
52-
return error("continuation cannot be performed twice")
53-
else
54-
return error(r)
55-
end
39+
40+
local resend = function(op, arg, k)
41+
return yield(call(op, {arg, type = throwT.resend}, k) )
5642
end
5743

58-
local gen_continue = function(co, handle)
59-
return function(arg)
60-
local st, r = resume(co, arg)
61-
if not st then
62-
return handle_error_message(r)
63-
else
64-
return handle(r)
65-
end
66-
end
44+
local is_eff_obj = function(obj)
45+
return type(obj) == "table" and (obj.type == callT)
6746
end
6847

6948
local handler
70-
handler = function(eff, vh, effh)
71-
local eff_type = eff.eff
72-
49+
handler = function(op, vh, effh)
7350
return function(th)
7451
local co = create(th)
7552

7653
local handle
77-
local continue
78-
79-
local rehandle = function(k)
80-
return function(arg)
81-
return handler(eff, continue, effh)(function()
82-
return k(arg)
83-
end)
54+
local handler_ do
55+
local vh_ = function(arg)
56+
return handle(resume(co, arg))
8457
end
58+
59+
handler_ = handler(op, vh_, effh)
8560
end
8661

8762
handle = function(r)
8863
if not is_eff_obj(r) then
8964
return vh(r)
9065
end
9166

92-
if r.cls == inst.cls then
93-
if r.eff == eff_type then
94-
return effh(r.arg, continue)
67+
if r.type == callT then
68+
local resended = r.x.type
69+
local k
70+
71+
if resended then
72+
k = function(arg)
73+
return handler_(function()
74+
return r.k(arg)
75+
end)
76+
end
9577
else
96-
return Resend(r, function(arg)
97-
return continue(arg)
98-
end)
78+
k = function(arg)
79+
return handle(r.k(arg))
80+
end
9981
end
100-
elseif r.cls == Resend.cls then
101-
if r.eff == eff_type then
102-
return effh(r.arg, rehandle(r.continue))
82+
83+
local arg = r.x[1]
84+
if r.op == op then
85+
return effh(arg, k)
10386
else
104-
return Resend(r, rehandle(r.continue))
87+
return resend(r.op, arg, k)
10588
end
10689
end
10790
end
10891

109-
continue = function(arg)
110-
local st, r = resume(co, arg)
111-
if not st then
112-
return handle_error_message(r)
113-
else
114-
return handle(r)
115-
end
116-
end
117-
118-
return continue(nil)
92+
return handle(resume(co, nil))
11993
end
12094
end
12195

test/state2.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ local foo = function()
9595
assert(21 == is.get())
9696
ss.put("world")
9797
is.get()
98+
print("OK!")
9899

99100
local t = {42, 21}
100101
local hs = is.history()

0 commit comments

Comments
 (0)