プログラム言語 SBF (2)

少し前に Haskell & Parsec で書いた S式→Brainf*ck のトランスレータですが、

http://d.hatena.ne.jp/shinichiro_h/20060630#1151631380

前回言ってた破壊して良いとか悪いとかのチェックとかその他高速化とかをすぐ実装してたり、うまくいかなかったりしてたんですが置いてなかったので置いておきます。

http://shinh.skr.jp/koneta/sbf.hs

うまくいかなかった部分はもう忘れましたがなんかつまり Haskell やっぱ俺にはつらいぞと思ったことは思い出せます。なんか要するに手続き脳がなんでも do モナド内に書かせようと要求してきてアレなのと、それとモナド返す関数とそうじゃない関数で引数の取り方を変えにゃならんとかが妙にストレスで、そのせいで関数を適切な粒度で切り分けるとかがめんどくさくなってコードのコピペが増えて保守しにくくなって…って自業自得じゃね、と思いつつ。あとそもそも最初の方針を色々間違ってて、大幅に書き換えたいけど保守しにくいコードになってて…っていうのも自業自得。

で、前回の大文字を小文字化 echo は、元のソース自体に手を入れたり適当に命令を増やしたりして、

(let (x (getchar))
  (while x
    (let (y (> x 64))
      (if y
          (if (> 27 y)
              (+= x 32))))
    (putchar x)
    (getchar! x)
    ))

というものが

,[>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>[-]<<[->>+>+
<<<]>>>[-<<<+>>>][-]<<[>[->+>+<<]>>[-<<+>>]<[[-]<->]<<-][-]>>>[-]<<[->>+<<<+>]<[
->+<][-]>>>[[-]<<<+++++++++++++++++++++++++++>>>[-]<<<[->>>+<+<<]>>[-<<+>>][-][-
]<[->+<<+>]<[->+<][-]>>[>[-<<<+>>>>+<]>[-<+>]<<<<[[-]>>>-<<<]>>-]<<[-]>>>[[-]<<<
<++++++++++++++++++++++++++++++++>>>>][-]]<<<<.,]

の 370Byte までは小さくできました。もう少しできるはずなんですが前述のうまくいかんかった部分がほげほげです。

あとまぁついでに、以前 C と Haskell で小さいコード書いてた PKU1519 を解く Brainf*ck コードを作ってみました。

(let (y 20)
  (let (x (getchar))
    (-= x 48)
    (while x
      (if (> y x)
          (while (> x 9)
            (-= x 9)))
      (if (> x y)
          (+= x 86)
          (putchar x)
          (putchar 10)
          (= x 0))
      (+= x (getchar))
      (-= x 48)
      )
    ))

を変換すると、

++++++++++++++++++++>,------------------------------------------------[>[-]<<[->
>+>+<<<]>>>[-<<<+>>>][-][-]<<[->>+>+<<<]>>>[-<<<+>>>][-]<[<[->>+>+<<<]>>>[-<<<+>
>>]<[[-]<<->>]<-]<[[-]>>>+++++++++<[-]<<<[->>>+<+<<]>>[-<<+>>][-]>>[<[-<+>>>+<<]
>>[-<<+>>]<<<[[-]>-<]>>-][-]<[<<<--------->>>>+++++++++<[-]<<<[->>>+<+<<]>>[-<<+
>>][-]>>[<[-<+>>>+<<]>>[-<<+>>]<<<[[-]>-<]>>-][-]<][-]<<][-][-]<[->+>>+<<<]>>>[-
<<<+>>>][-][-]<<<<[->>>>+>+<<<<<]>>>>>[-<<<<<+>>>>>][-]<[<<[->>>+>+<<<<]>>>>[-<<
<<+>>>>]<[[-]<<<->>>]<-]<<[[-]<+++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++.>>>>>++++++++++.[-]<<<<<[-]>][-],[-<+>>>>+
<<<]>>>[-<<<+>>>][-]<<<[-]<------------------------------------------------]

とかで 717Byte でした。サイズは大きいんですけど、お題があったら結構いきなりポンと Brainf*ck のコードを置けるのはなんか良いなと思いました。ちなみに、 前のバイトコードに変換しても 288Byte とかあったので、 C にすら遠く及ばなくて残念というか。普通に 3bit ずつでエンコードしたとすると 269Byte 。まぁまともに作ってないからしょうがないですが全然ダメ。

あと SBF に関しては要は変数以外は全部忘れていいメモリなので問題ないです とか書こうかなとしつつも、正直シロウトでよーわかっとらんのよねというのもあってほげほげと思ってたら k.inaba さんが文献つきとかでコメントして下さっていて、棚ボタというか。

あとまぁ偉大な wo さんはともかく私は「よくわかってないけどとりあえず概要だけ知ってみて知ったかぶりをする」のが趣味なのでなんもすごくないんですが、逆に、素人だから恥ずかしげもなく好き勝手言えるというのは常々良いことだなぁと思っています。どうも来年から素人でもなくなるようなのそうも言ってられんかもですけど。

追記:

後者の方、適当に命令増やして短縮。

(let (c (getchar))
  (-= c 10)
  (let (x 0)
    (= x c)
    (-= x 38)
    (while x
      (let (a (! c))
        (if a
          (-= x 2))
        (while (> x 9)
          (-= x 9))
        (if a
          (+= x 48)
          (putchar x)
          (putchar 10)
          (= x 0)))
      (getchar! c)
      (-= c 10)
      (+= x c)
      (-= x 38)
      )
    ))

コンパイルして、

,---------->[-]<[->+>+<<]>>[-<<+>>][-]<--------------------------------------[>>
[-]<<<[->>>+>+<<<<]>>>>[-<<<<+>>>>][-]<[[-]<+>]<->[-]<[->+>+<<]>>[-<<+>>][-]<[[-
]<<-->>]+++++++++>[-]<<<[->>>+>+<<<<]>>>>[-<<<<+>>>>][-]<<[>[->+>+<<]>>[-<<+>>]<
[[-]<->]<<-][-]>[<<<--------->>+++++++++>[-]<<<[->>>+>+<<<<]>>>>[-<<<<+>>>>][-]<
<[>[->+>+<<]>>[-<<+>>]<[[-]<->]<<-][-]>][-]<[-]<[->+>>>+<<<<]>>>>[-<<<<+>>>>][-]
<<<[[-]<<++++++++++++++++++++++++++++++++++++++++++++++++.>>>++++++++++.[-]<<<[-
]>>]<<<,----------[->+>+<<]>>[-<<+>>][-]<--------------------------------------]

の 560Byte 。

なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h