例えば JavaScript で
let x = (() => { let y = foo; return bar(y); })();
を
let y = foo; let x = bar(y);
my $x = do { my $y = foo; bar($y); };
を
my $y = foo; my $x = bar($y);
と書き換えても良かったりするように, Haskell でも
do { x <- do { y <- foo; bar y; }; baz x }
を
do { y <- foo; x <- bar y; baz x }
と書き換えても良いのだろうか, という話.
もし IO
であるならば良さそうな気がするが, 一般のモナドでもこのような書き換えは可能なのだろうかと思った.
結論から言うと, 書き換えて良い.
なぜ
きちんと等価になっていることを示す.
まず,
do { x <- do { y <- foo; bar y; }; baz x }
を do
を使わずに書き直すと,
(foo >>= (\y -> bar y)) >>= (\x -> baz x)
さらに無駄な部分を省略すると,
(foo >>= bar) >>= (\x -> baz x)
となる.
ここでモナド則 (m >>= f) >>= g
= m >>= (\x -> f x >>= g)
を用いて書き換えると,
foo >>= (\y -> bar y >>= (\x -> baz x))
とできる.
これは do
を用いて
do { y <- foo; x <- bar y; baz x }
と書いたものと等価になっている.
よかったね.
*1:もちろん前後で他に変数 y が使われていない場合に限るが, そういう場合は適当に変数名を変えれば良い.