Euler 4: Finding Palindroms を Squeak Smalltalk で


ひさしぶりにPythonシェイプアップ - 西尾泰和のはてなダイアリー 経由で http://blog.bestinclass.dk/index.php/2009/10/python-vs-clojure-evolving/Clojure のコード

(reduce max
    (filter #(let [s (str %)]
               (= (seq s) (reverse s)))
            (for [x (range 100 1000)
                  y (range 100 1000)]
              (* x y))))


これと似たようなことを Squeak Smalltalk の #asDigitsToPower:do: を使って書くと

| max |
max := 0.
(100 to: 1000) asDigitsToPower: 2 do: [:pair |
   | s |
   s := (pair first * pair second) asString.
   s reversed = s ifTrue: [max := max max: s asInteger]].
max   "-> 906609 "


まあ、Python の簡潔さにはかないませんね。^^;


ちなみに #asDigitsToPower:do: は、レシーバの要素に対して、第一引数で指定した個数の、重複を許す全順列で第二引数のブロックを逐次評価するメソッドで、ネストした繰り返し処理と同様のことを可能にします。

World findATranscript: nil.
(1 to: 3) asDigitsToPower: 2 do: [:each | Transcript cr; show: each]
#(1 1)
#(1 2)
#(1 3)
#(2 1)
#(2 2)
#(2 3)
#(3 1)
#(3 2)
#(3 3)


ちょっとややこしくなりますが、別の方向からですと

| xs ys seq max |
xs := (100 to: 1000) readStream.
ys := (100 to: 1000) readStream.
seq := [[((xs next ifNil: [ys next. xs reset next]) * ys peek) asString] ifError: []].
max := 0.
[(seq value ifNotNilDo: [:s |
   s reversed = s ifTrue: [max := max max: s asInteger]]; yourself) notNil] whileTrue.
max   "=> 906609 "


Ruby でも Enumerator#peek が使えるようになるらしいので、それを踏まえて直訳っぽく変換するとこんなかんじでしょうか。

xs = (100 .. 1000).each
ys = (100 .. 1000).each
seq = proc{((xs.next rescue (ys.next; xs.rewind.next)) * ys.peek).to_s rescue nil}
max = 0
while (s = seq[]) do (max = [max, s.to_i].max) if s.reverse == s end
p max   #=> 906609