プログラムで問題を教えるということ

また日記の間があいてしまった。
このエントリーは、プログラミングを教えることについての話ではないことに注意。ある問題がある。この問題をどういう手続きを用いれば解くことができるか、という手続きを教えたいということ。それこそがプログラミングの本質という意見もあるかも知れない。しかし個人的にはそれは違うと考えているのでこのエントリーを書く。なお、以下の話はよく考えるとちょっと頭が悪い話になる。あと、使用されている言語は特に何も考えていない。ちょっとPascalとかを思わせる言語になっているような気もするが。
たとえば、だ。4つの変数a, b, c, dがあるとする。ある2引数関数fooを、これらの変数のうち相異なるものについてすべて作用させたい。ただし、foo(a, b)とfoo(b, a)は両方実行する必要がある。
つまり、

foo(a, b);
foo(a, c);
foo(a, d);
foo(b, a);
foo(b, c);
foo(b, d);
foo(c, a);
foo(c, b);
foo(c, d);
foo(d, a);
foo(d, b);
foo(d, c);

と書きたい。全部で12行。ちょっとプログラムを知っている人であれば、言語にもよるが次のように書くだろう。

array = {a, b, c, d};
for i=1..4
  for j = 1..4
    if i != j
       foo(array[i], array[j]);
    end
  end
end

もし仮に、a, b, c, dという4変数が10変数になったとしても、ちょっと書き換えればそのまま使うことができる。さらにiとjのループをsize(array)回にしておけば、配列を書き換えるだけでいい。保守性に優れたbetterなコードだ。保守するつもりなら。
ところが、教育で使うのであれば、保守性はあまり問われない。求められることは、「難読でないこと」と「バグがないこと」の二点だけだ。「バグがないこと」において、冗長なプログラムは悪くなりうるが、この例のように4変数くらいならバグが入る余地は極めて少ない。それどころか、たとえば、下の例のようにi != jというところがi=jとかになってしまったりするようなバグだってありうるのだから、一長一短だ。そもそも、動作確認するのは当たり前なので、そこで動いていればあまり問題はないだろう。
重要なのはむしろ、どちらの方が読みやすいのか、だ。どちらが読みやすく感じるだろうか。意味が伝わりやすいだろうか。後者のプログラム方が、伝わりやすいという人は、おそらく相当にプログラムを読みなれている人だと思う。ただそういう人は、無意識的に後者の例のforループを展開しているんだと思っている。
で、だ。何が言いたいかといえば、個人的に前者の例は悪くないのではないかと。一部の学生に、後ろ指を指されて笑われるというリスクさえ取れば、あとは問題にならないのではないだろうかと。で、そんな学生に笑われたところでどうかなるような、そんな神経の細い人は教えるのに向いてないと思われるので(暴論)、やっぱり前者でいいんじゃないのかな、と最近思った。