async/awaitとpromise使えばモナド糖衣構文っぽいの書けそうだよねって思って書いてみたけど、async () => {} でwrapしないといけないしまぁそんなにきれいに書けなかったって話
タイトルで全部言い切ってますが
// Optional container like maybe monad class Option { constructor(value){ this.value = value } async promise() { return new Promise((resolve, reject) => { if (this.value) { resolve(this.value); } else { reject(undefined); } }); } }
こんなMaybe とかOptionalっぽいやつを用意します。 promise()
で Promiseを生成して返すようにします。もってる値に応じて resolve
(JustやSome)したり reject
(Nothing)したりします。
const o1 = new Option("foo"); const o2 = new Option("bar"); const o3 = new Option(null); (async () => { try { const v1 = await o1.promise(); const v2 = await o2.promise(); console.log(v1, v2); } catch {} })(); // => foo bar (async () => { try { const v1 = await o1.promise(); const v2 = await o2.promise(); const v3 = await o3.promise(); console.log(v1, v2, v3); } catch {} })(); // do nothing // introduce doM emulates do-like syntax sugar async function doM(f1, f2) { try { return f1(); } catch { if (f2) { return f2(); } } } // => foo bar
asyncの中で、 promise()
を awaitで呼び出すことで、 do記法っぽいあれ……に見えなくもなくないコードになりました。でも失敗系処理しない場合でも catch
書く必要あるのダルいですね?
try..catch
を変わりにやってくれるヘルパーを導入しましょう
// introduce doM emulates do-like syntax sugar async function doM(f1, f2) { try { return f1(); } catch { if (f2) { return f2(); } } }
この doM
に asyncな無名関数を渡すと、その中でdo記法っぽいあれ……に見えなくもなくないコードを書けます。
doM(async () => { const v1 = await o1.promise(); const v2 = await o2.promise(); console.log(v1, v2); }); // => foo bar doM(async () => { const v1 = await o1.promise(); const v2 = await o2.promise(); const v3 = await o3.promise(); console.log(v1, v2, v3); }); // do nothing
だからどうしたって話ですが、いろいろなモナドを作って合成して扱う場合に便利かもしれないですがそもそもモナドとかJavaScriptで作るな。以上