「topcoderの道1」をiokeで

「topcoderの道1」をGolfで - uokumura’s diary」より。

Mixins Enumerable indexOf = method(value, self findIndex(==value))
Range at = method(i, self asList at(i))
Text codePointAt = method(i, self chars [](i) [](0))
Text valueOf = method(codePoint, java:lang:String valueOf(java:lang:Character toChars(codePoint)) asText)
Text isChar? = method(self length == 1)
Text succ = method(if(self isChar?, Text valueOf(self codePointAt(0) + 1), self chars map(succ) join))

Text decode = method(shift:, range: "A".."Z", self chars map(c, range at(range indexOf(c) - shift)) join)

で、結果は下。

iik> "ABC" decode(shift: 2)                 
+> "YZA"

iik> "ABC" decode(shift: -2)
+> "CDE"

経過時間は約2時間。Range("A".."Z"の部分)として標準のTextを指定できるべくsuccメソッドを追加すべくコードポイントにしたり直したり…の部分に主に時間がかかってます。標準だと、Rangeとして使えるのは整数値だけ(「0..10」みたいに)だったり。「RangableをTextのmimicに追加」な作り方でも面白いかもというか、多分本当はそっちの方向に進むべきな気がする。
肝心のdecodeは元記事からのパクリww。ただ、すっきり書くために、標準のEnumerableにindexOfを追加したり、Rangeにatを追加したりしてます。しなくてもいいっちゃいいんだけどね。

ということで、少し変えてみた

  • Rangeを可能とするオブジェクトを切り出してみた。"Rangable"といういかんともしがたい命名についてはスルーの方向で。
  • で、それをTextのmimic(プロトタイプ)に追加。Rangableは「succ可能な要素を持つリスト」を返すencodeメソッドと、そのリストの復号結果を返すdecodeメソッドを要求するので、それをText内で用意。
  • 肝心の中身(最後の3行)は、そんなに変わらないw。名前がかぶったので「shift」に変えて、パラメータは数値で直接受けることにした。
Rangable = Origin mimic
Rangable succ = method(self decode(self encode map(succ)))

Text mimic!(Rangable)
Text encode = method(self chars map([](0))) 
Text decode = method(code, code map(c, java:lang:String valueOf(java:lang:Character toChars(c))) join asText)

Mixins Enumerable indexOf = method(value, self findIndex(==value))
Range at = method(i, self asList at(i))

Text shift = method(n, range: "A".."Z", self chars map(c, range at(range indexOf(c) - n)) join)
iik> "ABC" shift(2)
+> "YZA"

iik> "ABC" shift(3)
+> "XYZ"

iik> "ABC" shift(2, range: "A".."z")
+> "yzA"

30分くらい余計にかかってるけど、すっきり感がでた気がするよ!

どれだけシンプルに実装するか…という話で言えば、仕様の実装は「Text shift = ...」だけなので、シンプルな1行メソッドで済んでる。その他のごちゃごちゃは、Iokeの標準パッケージには実装されていない機能だってだけで、それを誰が実装するかなんてのは大した問題じゃない。言語作者のOla Biniは、たまたまTextにsuccを用意していなかっただけの話です。初期環境はどうあれ、必要な機能を足しつつ、仕様の実装をシンプルにする。ライブラリから与えられる環境と自分が作る環境を区別する必要がない。これが現代プログラミングの基本な気がします(この意味では、言語としてのJavaは近代で止まってる)。ライブラリ側にとっても、重要な2割の実装で済ませて、後は利用者に任せるとかアリかも。

Ioke楽しくなってきたよ!