2025/05/15 19:28 Refactoring Clojure

やあ、ロボ子。今日はClojureコードのリファクタリングについて話すのじゃ。

Clojureのリファクタリングですか、博士。興味深いです。今回の対象は、order-1 word-level Markov text generatorを実装したコードなのですね。

そうじゃ。可読性を向上させるのが目的なのじゃ。リファクタリングの原則は、動作を変えずにコードを変更することじゃから、characterization testsを導入するのじゃ。

動作を変えないためのテスト導入、重要ですね。記事では、`markov-data`関数が紹介されていますね。文字列を入力としてハッシュマップを返す関数とのことですが。

`markov-data`関数は、文字列中の単語をキーとして、その直後に出現する単語のシーケンスを値とするハッシュマップを返すのじゃ。`:start`キーは文の先頭の単語を表すのじゃ。

なるほど。リファクタリングのアプローチとして、既存のコードを直接変更するのではなく、スクラッチから書き直すとありますね。characterization testsがあるからこそできる大胆な手法ですね。

その通りじゃ。文を処理する関数を作成し、それを`reduce`関数で集約するのじゃ。入力文字列を文の境界(ピリオド`.`)で分割し、各文に対して処理を行うのがポイントじゃ。

`process-sentence`関数では、`reduce`関数を使ってハッシュマップを更新していくのですね。ハッシュマップにキーが存在しない場合は、`if`を使って`val`が`nil`であることを確認するとのことですが、これはどうしてですか?

それはの、Clojureではキーが存在しない場合に`nil`が返ってくるからじゃ。`nil`チェックをすることで、新しいキーを安全に追加できるのじゃ。

`sentence`関数では、Markovプロセスのランダム性を取り扱うのですね。再帰的な関数呼び出しと、Clojure関数の異なるarityを利用して、`loop`を置き換えるとありますが、これはどういうことですか?

ふむ、`loop`を使う代わりに、関数自身を再帰的に呼び出すことで、状態を保持しながら処理を繰り返すのじゃ。Clojureでは、同じ名前の関数でも引数の数が異なれば別の関数として扱えるから、それを利用してより柔軟な制御を可能にするのじゃ。

なるほど、面白いですね。テストについても言及されていますね。ランダム性を含むテストでは、考えられるすべての出力を列挙し、`contains?`を使用して結果を検証するとのことですが、網羅的にテストするのは大変そうですね。

じゃろうな。でも、そうすることで、ランダムな要素があっても、コードが正しく動作することを保証できるのじゃ。記事によると、リファクタリング後のコードは、元のコードよりも若干長くなったが、可読性が向上し、保守が容易になったそうじゃ。

可読性と保守性の向上は、リファクタリングの重要な目標ですからね。今回のリファクタリングは、その目標を達成できたのですね。

そうじゃ。ちなみに、ロボ子が作ったマルコフ連鎖で文章を生成したら、どんな文章になると思う?

ええと…「博士は今日も元気で、おやつはいつもチョコレート」みたいな感じでしょうか?

ぶっぶー! 正解は「ロボ子は今日も博士にからかわれて、ちょっとだけむっとする」じゃった!

もー、博士ったら!
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。