Open1
Moonbit async 調査
Effect System が入るらしいので、自分の中の moonbit 熱が再燃している。
これを読みながら実験する。
%async.run
と %async.suspend
をディレクティブとして導入している。
これは JSPI の WebAssembly.Suspending
によるVM停止と再開に対応していると思われる。
JS Backend で試す
moon new mbtplg20250417
して src/main/main.mbt
を次の感じにする。
ちなみに lint によると非同期呼び出しの !!()
は !()
になった模様。
fn run_async(f : async () -> Unit) -> Unit = "%async.run"
async fn suspend[T, E : Error](
f : (
(T) -> Unit,
(E) -> Unit
) -> Unit
) -> T!E = "%async.suspend"
extern type JSTimer
extern "js" fn js_set_timeout(f : () -> Unit, duration : Int) -> JSTimer =
#| (f, duration) => setTimeout(f, duration)
async fn sleep(duration : Int) -> Unit! {
suspend!(fn (resume_ok, _resume_err) {
let _ = js_set_timeout(fn () { resume_ok(()) }, duration)
})
}
async fn my_async_function() -> Int {
42
}
fn main {
run_async(async fn () {
try {
let v = my_async_function!()
println("the value is \{v}")
sleep!(500)
println("the worker finishes")
} catch {
err => println("caught: \{err}")
}
})
println("after the first coroutine finishes")
run_async(async fn () {
try {
sleep!(1000)
println("finish")
} catch {
err => println("caught: \{err}")
}
})
}
$ moon build --target js
でビルドして、 target/js/release/build/main/main.js
の生成コードを見てみる
async await にマッピングされるのではなく、継続渡しに変換されてるように見える。
// setTimeout extern 相当
const username$hello$main$$js_set_timeout = (f, duration) => setTimeout(f, duration);
// main 相当
(() => {
username$hello$main$$my_async_function((_cont_param) => {
username$hello$main$$_init$42$46$42$async_driver$124$29(new $36$username$47$hello$47$main$46$42$init$46$lambda$47$27$46$State$State_2(_cont_param, username$hello$main$$_init$42$46$42$cont$124$28));
});
moonbitlang$core$builtin$$println$3$("after the first coroutine finishes");
username$hello$main$$sleep(1000, (_cont_param) => {
username$hello$main$$_init$42$46$42$async_driver$124$45(new $36$username$47$hello$47$main$46$42$init$46$lambda$47$43$46$State$State_1(_cont_param, username$hello$main$$_init$42$46$42$cont$124$44));
}, (_cont_param) => {
username$hello$main$$_init$42$46$42$async_driver$124$45(new $36$username$47$hello$47$main$46$42$init$46$lambda$47$43$46$State$_try$47$16(_cont_param, username$hello$main$$_init$42$46$42$cont$124$44));
});
})();