関数とは、手続きを書く場所を移動させるためにあるのではない
プログラム言語における関数とは、手続きを書く場所を移動させるためにあるのではない。単純で明確な意味を持つ言葉を定義すること。言葉を組み合わせて無限の意味を表すのが、まさに「言語」の本質。そのためには、関数のI/Oを最小化すること。便利かもしれないと誤解して、無駄に制御引数を増やした関数は、まるでシェルコマンドのようで、言語の価値を低下させかねない。
課題:「野球観戦。7回までは試合結果を観戦、7回以降は試合結果を録画」を言語で表現してみる。
試合=gameに、観戦と録画を切り替えるモードフラグを持たせ、回の範囲を指定できるように考えた。
score = 0 def game(watch_or_record, start, end): global score for r in xrange(start, end+1): score += play(r) if watch_or_record: watch(score) else: record(score) game(True, 1, 6) game(False, 7, 9)
これじゃ手続きを書く場所を変えているだけ。最後の2行、引数順序を忘れると意味が読めなくなるし、1と9という整数の範囲を間違えると、野球じゃなくなる。
こんな関数は展開したほうがマシだ。
score = 0 for r in xrange(1, 7): score += play(r) watch(score) for r in xrange(7, 10): score += play(r) record(score)
ね。
いっぽう、野球の回の「まで」と「以降」、それと試合することを意味的に分けてみる。
def before(c): return xrange(1, c) def after(c): return xrange(c, 9+1) score = 0 def game(round): global score for r in round: score += play(r) return score watch(game(before(7))) record(game(after(7)))
before/afterの引数は1つで、意味を見失うことはないし、また、watch/recordをクライアントコードに任せることで、観戦/録画以外の選択肢も与えられる。クライアントコードが管理する変数は 7 だけになる。
さて、いつも使っているAPIに
game(True, 1, 6) game(False, 7, 9)
みたいなのがどのぐらいあるだろう?