アンチネスト構文
↓これ途中で概念がごっちゃになってて、以下は区別すべき
a) 単純にネストを減らすもの
JSのawait、Kokaのwith
b) 各行を関数呼び出しに変換するもの
Haskellのdo、Scalaのfor
----
#shiika
Haskellのdo、Scalaのfor、F#のコンピュテーション式みたいなものを入れたらどうか
「みたいなもの」とは
手続き型っぽい記法が、関数呼び出しのチェーンに展開される記法
いろんな用途に使える
いろんな用途とは
Resultをまとめる (Rustでいう? )
async-await
Haskellのdo
https://en.wikibooks.org/wiki/Haskell/do_notation
Scalaのfor
https://www.ne.jp/asahi/hishidama/home/tech/scala/collection/for.html
map, flatMapとかに展開される
(2022-06追記) Kokaのwith
/nekketsuuu/Kokaの特徴的な文法
with以降、関数末尾までがクロージャになる
検討事項
目印をどうするか (do for のようにキーワードにするのか、しないのか)
code:shiika
# --- Array
result = for {
x <- 1,2,3
y <- 4,5,6
x * y
}
#=> 4,5,6,8,10,12,12,15,18
# 変換後
result = 1,2,3.flat_map{|x|
4,5,6.map{|y|
x * y
}
}
# --- Maybe
for {
name <- user.name
book <- Book.find_first_by_author(name: name)
book.title
}
# 変換後
user.name.flat_map{|name| # nameがNoneのときはブロックを実行せずNoneを返す
Book.find_first_by_author(name: name).map{|book| # bookがNoneのときはブロックを実行せずNoneを返す
book.title # bookがSomeのときは中身をyieldしてSomeを返す
}
}
# --- Result
for {
x <- task1
task2
task3(x)
}
# 変換後
task1().flat_map{|x| # task1の結果がErrのときはブロックを実行せずErrを返す
task2().map{||
task3(x)
}
}
# --- 非同期
task = for {
x <- get_from_network
y <- heavy_processing(x)
send_and_wait(y)
}
task.run
# 変換後
get_from_network.flat_map{|x|
heavy_processing(x).map{|y|
send_and_wait(y)
}
}
メモ
scalaだとforeachに展開されるものがあるらしい
全部map/flat_mapにしてしまうと巨大な配列ができて困ることがあるだろうか?
モナドには高階多相が必要?
async/awaitと合成可能性 | κeenのHappy Hacκing Blog
多相について今一度調べてみた - 壁は登るためにある
F#のコンピュテーション式はモナドが実装できるが、F#に高階多相はない
と教えてもらった https://twitter.com/vain0x/status/1359470333598736384
これは朗報
SwiftのFunction Builderが似てる?
https://qiita.com/kentrino/items/dc6e77a0ddd21187cc55#tldr
2022-06
Algebraic Effectsのperformがこれだな
await、yieldってperformで書けるのかな