オブジェクト指向でモナドするならメソッドチェーンで書くと自然になるかも
オブジェクト指向の言語でモナドっぽいことをするなら、メソッドチェーンできるように実装すると自然になるかなと思った。
JavaScript では Promise がモナドなのだけど、 bind 的なことをしているのは then なわけです。
// doSomethingAsync の型が number -> Promise<number> だとして
Promise.resolve(1)
.then(doSomethingAsync)
で、 Promise といえば then のメソッドチェーンで(めんどくさいけど)良い感じに書ける。
そこで、Promise と同じ気持ちで副作用を扱うモナドが作れる side-eff というライブラリを作ってみた。
例をつけて説明します。
まず、 SideEff を継承したクラスの中で affect メソッドに副作用のある関数を定義します。ここでは Message クラスがそれ。 affect メソッドの中でグローバル変数にアクセスして値を書き換えます。
Message クラスのコンストラクタは 2 つの引数を受け取ります。第一引数が外に取り出せる値で、第二引数が affect メソッドに渡す値です。
次に、純粋な関数をいくつか定義します。例では、 add5, multple2, square です。それぞれの関数は Message のインスタンスを返すようにします。
それから、メソッドチェーンを作ります。 SideEff の affectThen は副作用のある affect をしれっと実行してから、値を"むいて"次の関数に渡します。たとえば.affectThen(add5) の挙動は、 affect('Start') を実行してから、 add5 に 1 を渡し、 new Message(6, 'Add 5') を返します。
メソッドチェーンの最後 .unwrap() は affect を実行してから値を取り出すことをします。 変数 result には 144 (= ((1 + 5) * 2) ^ 2) が入ります。
メソッドチェーンの背後で affect が呼ばれているので、グローバル変数 message が変更され、その値は最終的に、
Start Add 5 Multiple 2 Square
となっています。
説明するとなんか厄介ですが、 add5, multple2, square 達は純粋関数でありつつ、副作用の扱いを Message が一挙に引き受けて汚れ役になってくれているのがおわかりいただけますでしょうか。
このライブラリを実務で使うかというと別に使わないのですが、一つのデザインパターンとしてはありかなと思いました。