infix to postfix

1年以上前に出題された問題なのですが、当時 kinaba さんの解答を見て、すげーと思って、今でも一番好きな Ruby のコードではないかと思っています。ので思い出したように少し書いてみます。

http://www.kmonos.net/wlog/71.html#_2014070301

問題は、 (a-b)*c というような中置記法の式を、 ab-c* というような後置記法になおせというもの。 flagitious さんと kinaba さんは eval で ruby中置記法のパースを丸投げして、 method_missing に飛んできた順で出力する、という豪快な手法で当時最短だった 61B になったのでした。こんなの

undef:p
def method_missing s,*;$><<s end
loop{eval(gets)<<$/}

あまりにも美しいコードなんですが、3ヶ月程前に、 flagitious さんが 59B を叩き出して更新しました。で kinaba さんも追いついたのですが、どうも flagitious さんとの雑談によると、 2人のコードは違う気がしています(ほとんど alnum だと言ってた気がするので、後述する goruby の alnum 解に近いのではないかなぁと思うけどよくわからない)。 kinaba さんの方はおそらく

undef p
def method_missing s,*;$><<s end
eval [*$<]*'puts;'

という感じなのではないかと思います。思いついてしまえばなるほどまぁ普通かもという感じです。この解が出る前にずいぶん悩んだんですが、実は 60B を一度思いついていました。これはなかなか豪快な方法で、いつか使ってやると思っていた「def文は実は nil をかえしている」という事実を使いました。

undef p
eval(gets)<<$/until def method_missing s,*;$><<s end

次に goruby なんですが、 goruby は Kernel#h が定義されていて、これが Hello, world! を出してくれるんですが、この問題では余計なことを…! という感しかわいてきません。でかつ method_missing を定義して解くこの問題では、 method_missing でメソッド名が短くなる goruby の効能が消えてしまいます。だからこの問題は goruby 向いてない…と思っていたのですが、色々やってみると 40B とかいう驚異的なことになっていたのでした。

O.u:p,:h
O.a_ _,:print
eval [*$<]*'say;'

何してるかさっぱりわからんですが、

  • O.u は Object.undef_method
  • O.a_ は Object.alias_method
  • 第一引数の _ は奇跡的な事情により :method_missing になっている
    • Kernel#_ が存在しないので method_missing が呼ばれる
    • method_missing 内で _ に最初にマッチする関数である __callee__ が呼ばれる
    • この時 __callee__ は :method_missing
  • 第二引数の alias 先は print だけど、これは ruby 1.8 では使えない
    • ruby 1.8 では print nil は "nil" を表示してしまうから
    • まさかこんな変更がゴルフに、しかもこの問題に影響を及ぼすとは
  • あとは puts の変わりに say を使えば終わり

_ が :method_missing になっているのを最初に偶然発見した時は、しばし理由がわかりませんでした。

あとは flagitious さんが最初に投稿した、ほぼ alnum のバージョンもなかなか良いです。

undef p
undef h
alias method_missing print
say until eval gets
なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h