Hash λ Bye

Haskell, Clojureなどの話

Clojureでの副作用の表現について

自分が悩んでることを拙い語彙でぽつぽつ綴るので、誰にも伝わらないと思う。

DBアクセスする機能を実装したいとする。

java.jdbc を使ってDBアクセスレイヤを実装することになるのが普通かなと思う。 Clojure関数型プログラミング言語なので、組み立てに使う部品(関数)はできるだけ純粋な方がいい。 DBからのデータ取得やデータ更新を行う手続きもできるだけ副作用のない関数で組み立てたい。

DBアクセスする手続きなのにそんなことできるのか? と思う。

Haskellのように独自ASTとinterpreterのパターンならそれができる。 Clojureでも同じような構成になるのだろうか。

いくつかアプローチがありそうだ。

  1. 副作用を起こす関数は高階関数で受け取る
  2. 副作用を起こすコマンドを生成する純粋関数を合成し、interpreterで副作用を発行する

基本的には高階関数で解けるのが一番低コストでよいと思う。 高階関数を使ったDIだと捉えるとわかりやすい。

ただ適用する関数が色々な種類の副作用関数を要求するようになると突然複雑になる。DIで言えば注入する依存が肥大化している状態。 気軽に依存が満たせなくなるので、とても腰の重いインタフェースができる。

それを補うために関数の辞書を渡すことになってしまう。しかしインタフェースが抱える複雑さは変わらないので、実はあまり解決になってない。

2案

あるパラメータを渡すと「印字せよ」とか「INSERT文を発行せよ」という命令を返す関数を中心に組み合わせる。 命令は実行されるまで何の副作用も生まない。なので、その関数を呼び出しても、何か副作用が起きるわけではない。 実行すれば副作用が起こる命令が手元にあるだけだ。

これはDIとは完全に切れ離された、より純粋な設計になる。 しかし一方で、命令を実行する別の機能が必要になるため複雑さはそちらになお宿っている。

が、ビジネスドメインの記述に徹することができるのは保守上のメリットがある。

対して、命令と実行を受け持つ関数はなかなか軽くもシンプルにもならないだろうと思う。

それでもドメインを純粋に保てるのなら2案になるのかな。

設計プランは後ほど追記 - 4/23 まだできてない Clojureで遊んでいる場合ではない感じに。。。