読者です 読者をやめる 読者になる 読者になる

Codeへの愛とCuriosity

CodeIQ への出題・解説解題・その周辺について、思いつくままに。

逆リファクタリング問題

tbpgr さんの逆リファクタリング問題
https://codeiq.jp/magazine/2015/02/21347/
に挑戦した。

優秀解答として紹介していただいたので、解説する。

ソース

まずはソース。

#coding:utf-8
def static(*);yield if block_given?;:!end
alias void static
alias Main void
class System;def self.in; self;end;def self.eof; STDIN.eof?;end
def self.out;Kernel;end;def self.read; STDIN.getc;end;end
def If(x);yield if ($g=x);end
def Else;yield unless $g;end
def While(x);yield while x.(); end
class  BasicObject;def method_missing(method, *args);
args[0].upcase if args.size==1 && args[0].is_a?( "".class );end;end
alias   lambda

! 謎言語風です。
! 入出力がSystem.inだったりSystem.outだったりする辺りはJava風。
! メインがMainなのはC#風。
! コメントは苦し紛れに FORTRAN 風。
! もっとWhileを見慣れた感じにしたかったんだけど、これ以上アイディアがなく。

public static void Main(){
  string s=null;
  While  {! System.in.eof()} {
    If ( s==null ){
      s="";
    }
    Else{
      s=" "+upcase(s);
    }
    s=System.in.read()+s;
  }
  System.out.print(s);
}

全体的な話

実は、『Cプログラミング診断室』( http://www.amazon.co.jp/dp/4774117870 )の「第8章 Pascalが好き」へのオマージュのつもりで書き始めた。

ダメなソースコードの例が解説付きで載っている名著なので、未読の方は是非。

それはさておき。

当初は Java 風にしようとしていたんだけど、どうもうまく出来なくて。
特に while ループを

While(条件){ループ内}

のようにする方法がわからず、仕方なく謎言語風という形に逃げた。

順に解説

謎言語部に登場する部品を、概ね登場順に解説する。

FORTRAN風のコメント

FORTRAN 風のコメントは、普通に 否定演算子 + rubyメソッド呼び出しに なっている。
つまり「謎言語風です。」などはメソッド呼び出し。そんなメソッドはないんだけど、method_missing でエラーにならなくなる。
「! メインがMainなのはC#風。」の部分は、# 以下がrubyのコメントになっている。
ちなみに、
「! Mainメソッドが云々」
のようなコメントを書くと、大文字始まりなのでメソッドではなく定数になり、実行時エラーになる。

以下、method_missing に到達する処理を「無駄メソッド」と記述する。

public static void Main

public は ruby予約語……ではなく、Module クラスの private メソッド。static以下の実行結果を public にする。
static も void も Main もメソッドで、

static( void( Main(){略} ) )

ということになっている。
public に何かを渡さなくてはいけないので、static は「:!」を返している。
Main の引数のブロックを実行しなくてはいけないので、Main はブロックを受け取ったらそれを実行するようになっている。

string s=null;

型を指定して変数を宣言しているようにみえる

string s=null;

は、

string( s=null() )

という意味である。
string も null も無駄メソッドだけど、s は本当にローカル変数。

無駄メソッドは、引数がないと nil を返すようになっているので、これで

無駄メソッド( s=nil )

となり、無事、本当に s が nil になる。

While

難儀した割に無様な While なんだけど、

alias 全角空白 lambda

によって、While の部分は

While( lambda{条件} ){ ループ内 }

となる。
大文字なのは VB 風味とも言えるけど、while は ruby予約語なので逃げでもある。

System クラス

System.in.eof()

は、比較的普通な感じ。System クラスには以下の様な4つの特異メソッドがある。

メソッド 意味
in System クラスを返す
out Kernel クラスを返す
eof STDIN.eof?
read STDIN.getc

で。System.in.eof() は、System.eof() で、つまり STDIN.eof? になる。

最後の方にある System.in.read() は、System.read() なので、STDIN.getc になる。
一番最後の System.out.print(s) は、System.print(s) なので、Kernel.print(s)、つまり、print(s) になる。

If と Else

If( s==null ){ 真の場合 } Else { 偽の場合 }

は、Else のために $g というグローバル変数を使った。

If と Else 自体は、ブロック を受け取る普通のメソッド

upcase

upcase は定義されていないので、無駄メソッドである。つまり、

s=" "+upcase(s);

は、

s=" "+無駄メソッド(s);

である。
無駄メソッド
 「引数が1個でそれが文字列なら upcase した値を返す」
という処理になっているので、これで upcase になる。

まとめ

こうして書いてみると、工夫が足らんなあという気分になる。
もうちょっと馬鹿げた意味のわからないことを書きたかったなぁ。