2021年2月24日水曜日

抽象的思考力を鍛えるべし

やれ三項演算子は分かりにくいだの,ラムダ式は必要ないだの,なんだかそんなプログラマの皆さん,情けなくないか?オジサンは日本の凋落原因を間近に見ているような気がして,淋しくなってきたぞ?

三項演算子や再帰的定義を説明するのにmax(a, b)だのfib(n)だの,そういう易しい例を引き合いに出しているのは,「なるたけ易しい事例をもって分かりやすく説明しよう」という親心であって,別に,これらの概念がそういう易しい事例でしか適用できないっていうわけじゃない.

hilbert = (n, m) =>

  (n > 0) ? tm.forEach(mm => hilbert(n-1, mat_mul(m, mm)))

  : [ [0.25, 0.25], [0.25, 0.75], [0.75, 0.75], [0.75, 0.25] ]

        .map(p => affine_transform(m, p))

        .map(p => [p[0]*cs.width, p[1]*cs.height])

        .forEach(p => ctx.lineTo(p[0],p[1]))

たとえばこのコード.ヒルベルト曲線を描く関数の定義である.再帰的定義,三項演算子,写像(map)とラムダ式,メソッドチェーンなど,「知ってると役立つ」プログラミングの知識がてんこ盛りになっている.ここでラムダ式は陽には出てこないけれど,map()のカッコの中って実はラムダ式の概念以外のナニモノでもない.旧態依然とした手続き型の書き方からは大きく乖離した表現なので,一見して何をやっているのかよく分からない人もいるかもしれない. 実は(詳しく説明しないが)map()とforEach()を使い分けている点にも意味があるのだ(最後に線で繋ぐときに順番が重要になってくるからである).

さらにこのヒルベルト曲線のプログラムは,フラクタルの考え方(再帰と親和性が高い),アフィン変換,行列の掛け算で連続した座標変換を表現できること(数学!)を理解していないと全体像を掴むことはできない.しかし,そのような概念をきちんと理解できていれば,実に短いコードで複雑なヒルベルト曲線を描くことができる点に驚くはずだ.

まあ,三項演算子はif…else…で置き換えても構わない.先の関数定義ではそのほうが読みやすいという人もいるだろう.しかし,それ以外の知識は,「必要ない」じゃ済まされないのではなかろうか.それらを使わずヒルベルト曲線を描くプログラムを書けと言われたら,まあ,苦労して書けないことはないかもしれないけれど,私は,そんな苦労はしたくないなあ.

つまり,本稿で何を言いたいかというと,ちょっとした学習は負担に思うかもしれないが,結局は問題解決の近道になっているはずだということである.これまで様々な先人たちが切り拓いてきた道なのだから.急がば回れというやつか.まあ,ヒルベルト曲線が描けたところでどうだという話ではあるが,世の中のシステムトラブル事例なんかを見聞きしていると,老婆心ながら,こういうちょっとした努力を避けている連中が自ら墓穴を掘っているのではないかと思ってしまう.余計なお世話かな.

0 件のコメント:

コメントを投稿