昨日(2016年7月3日)、「F#談話室(23)」というconnpassの勉強会に誘われて出席した。F#のことは全く知らないし、話し合われていた内容のことは理解できなかったが「パイプライン便利だよー、パイプライン。」という言葉が気になったので、それがどういうものか質問してみた。
MSDNを見ると、「パイプライン処理を使用すると、複数の関数呼び出しを一連の操作として連結することができます。」として以下のような例が出ている。
let function1 x = x + 1
let function2 x = x * 2
let result = 100 |> function1 |> function2
上の場合、結果は 202 になる。← (100 + 1) * 2
懇親会の席でいろいろ聞いて「メソッドチェーンと意味合いは同様だけれども、外部関数を連結させられるのがポイントだ」とその場では理解した。とにかく左から右につなげて書くことで便利になる場合もあるのだろう。そこから先はまだわからない。
とりあえずパイプライン演算もどきをネタとしてVBAHaskellに追加してみる。
VBAでは構文上の制約から、メソッドチェーンで表現せざるを得ないし、処理の開始と終了はそれぞれ「オブジェクトの生成」と「値の取り出し」という形で明示的に書くしかなさそうだ。たいていの場合オブジェクトは使い捨てで十分だからNewするのではなく、pipeというファクトリ関数に初期値を与えて生成することにした。値の取り出しはProperty Getでいいだろう。
結論としては、下のような書き方のパイプラインもどきとなった。(コメントは削除する必要がある)
? pipe(3) _ ' 初期値 3 でオブジェクト生成
.→(p_plus(10)) _ ' + 10
.→(p_mult(10)) _ ' * 10
.→(p_minus(, 3)) _ ' - 3
.val ' 結果の取り出し
127
F#のような簡潔さはないし、もともとVBAHaskellにはfoldl_Funsやfoldr_Funsといった関数合成の方法はある。しかしそれらは関数列を配列で与えるので1回走らせたらそれで終わりだ。パイプラインの書き方だと途中経過を見たあと処理を再開をするといった使い方ができるので、使い道はあるかもしれない。
クラスモジュール(vh_pipe.cls)はかなり簡単にできた。
値を保持するVariant変数retを持ち、与えられた関数を適用した結果をswapで上書きしていくだけだ。
'vh_pipe.cls
Private ret As Variant
Public Function →(ByRef fun As Variant) As vh_pipe
swapVariant ret, applyFun(ret, fun)
Set → = Me
End Function
VBAHaskellの紹介 その25(乱数生成:メルセンヌ・ツイスタ mt19937)
VBAHaskellの紹介 その1 (最初はmapF)
GitHub VBAHaskell
リファレンス