Hatena::ブログ(Diary)

まめめも このページをアンテナに追加 RSSフィード

2009-09-16

[][][][][][][][][][][] quine リレー

Update (2013-07-15): I improved this program to 50-language version. 50 言語版にパワーアップさせました。


これはこのプログラム自身を出力する Unlambda プログラム、を出力する Whitespace プログラム、を出力する brainfuck プログラム、を出力する Java プログラム、を出力する C プログラム、を出力する Haskell プログラム、を出力する OCaml プログラム、を出力する Lua プログラム、を出力する Perl プログラム、を出力する Python プログラム、を出力する Ruby プログラム、です。

# ruby
l=92.chr;eval s="s=s.dump[r=1..-2].gsub(/("+l*4+"){4,}(?!\")/){|t|'\"+l*%d+\"'%(t
.size/2)};5.times{s=s.dump[r]};puts\"# python\\nprint(\\\"# perl\\\\nprint(\\\\\\
\"# lua"+l*4+"nprint("+l*7+"\"(* ocaml *)"+l*8+"nprint_endline"+l*15+"\"-- haskel
l"+l*16+"nimport Data.List;import Data.Bits;import Data.Char;main=putStrLn("+l*31
+"\"/* C */"+l*32+"n#include<stdio.h>"+l*32+"nint main(void){char*s[501]={"+l*31+
"\"++intercalate"+l*31+"\","+l*31+"\"(c(tail(init(show("+l*31+"\"/* Java */"+l*32
+"npublic class QuineRelay{public static void main(String[]a){String[]s={"+l*31+"
\"++intercalate"+l*31+"\","+l*31+"\"(c("+l*31+"\"brainfuck"+l*64+"n++++++++[>++++
<-]+++++++++>>++++++++++"+l*31+"\"++(concat(snd(mapAccumL h 2("+l*31+"\"110"+l*31
+"\"++g(length s)++"+l*31+"\"22111211100111112021111102011112120012"+l*31+"\"++co
ncatMap("+l*32+"c->let d=ord c in if d<11then"+l*31+"\"21002"+l*31+"\"else"+l*31+
"\"111"+l*31+"\"++g d++"+l*31+"\"22102"+l*31+"\")s++"+l*31+"\"2100211101012021122
2211211101000120211021120221102111000110120211202"+l*31+"\"))))))++"+l*31+"\","+l
*63+"\""+l*64+"n"+l*63+"\"};int i=0;for(;i<94;i++)System.out.print(s[i]);}}"+l*31
+"\")))))++"+l*31+"\",0};int i=0;for(;s[i];i++)printf("+l*63+"\"%s"+l*63+"\",s[i]
);puts("+l*63+"\""+l*63+"\");return 0;}"+l*31+"\");c s=map("+l*32+"s->"+l*31+"\""
+l*63+"\""+l*31+"\"++s++"+l*31+"\""+l*63+"\""+l*31+"\")(unfoldr t s);t[]=Nothing;
t s=Just(splitAt(if length s>w&&s!!w=='"+l*31+"\"'then 501else w)s);w=500;f 0=Not
hing;f x=Just((if x`mod`2>0then '0'else '1'),x`div`2);g x= reverse (unfoldr f x);
h p c=let d=ord c-48in(d,replicate(abs(p-d))(if d<p then '<'else '>')++"+l*31+"\"
."+l*31+"\");s="+l*31+"\"# ruby"+l*32+"n"+l*31+"\"++"+l*31+"\"l=92.chr;eval s=\"+
(z=l*31)+\"\\\"\"+s+z+\"\\\""+l*31+"\"++"+l*31+"\""+l*32+"n"+l*31+"\""+l*15+"\""+
l*7+"\")"+l*4+"n\\\\\\\")\\\")\"########### (c) Yusuke Endoh, 2009 ###########\n"

最初のコメント行以外の改行は読みやすさのために入れています。QuineRelay.rb などというファイルとして保存してください。以下のように実行します。

$ ruby QuineRelay.rb > QuineRelay.py
$ python QuineRelay.py > QuineRelay.pl
$ perl QuineRelay.pl > QuineRelay.lua
$ lua QuineRelay.lua > QuineRelay.ml
$ ocaml QuineRelay.ml > QuineRelay.hs
$ runghc QuineRelay.hs > QuineRelay.c
$ gcc -Wall -o QuineRelay QuineRelay.c && ./QuineRelay > QuineRelay.java
$ javac QuineRelay.java && java QuineRelay > QuineRelay.bf
$ beef QuineRelay.bf > QuineRelay.ws
$ wspace QuineRelay.ws > QuineRelay.unl
$ unlambda QuineRelay.unl > QuineRelay2.rb

最終的に得られる出力 QuineRelay2.rb は最初の Ruby プログラムと一致するはず。

$ diff QuineRelay.rb QuineRelay2.rb

念のため各処理系バージョンを書いておきます。すべて Debian/lennyaptインストールできるものです。

2009-08-30

[] OCaml Meeting Tokyo 2009 に参加した

ref: http://ocaml.jp/?Users%20Meeting

ref: http://atnd.org/events/738

参加しました。どんな人が集まるのかわくわくしていましたが、OCaml に触ったことがない人から OCaml のスーパーハッカーまでいろんな人が集まってました。ぼくはというと、ここ数年ほとんど OCaml 触ってませんでした。

発表はどれも面白かったです。特に Ocsigen は見てみたくなった。ちゃんとしたもの作るときには Rails なんかよりよっぽど筋がよさそう。あと OCaml 開発のテストの実態も大したことないらしくてよかった。そういえば OCaml on iPhone の話とか聞きたかったかもしれない。

OCaml Golf Competition にも参戦。ひさびさの OCaml でひさびさのゴルフ。最初は素因数分解で書いていて全然ダメだった。1 から n/2 までで約数を探しまくる馬鹿サーチでも間に合うことがわかってからは、過去の Golf の中野さんの OCaml コードを読みあさって縮めていった。if then else を使わない方法で 109B になり、n/d*d/n*d という怪しい式を発見して 104B くらいになった。それからオプショナル引数に気がついて 97B になった。前日の時点でここまできていたけど、もう伸びなかった。

はじめましてだった人も、お久しぶりだった人も、主催者の古瀬さん、小笠原さん、ocaml-nagoya のみなさんも、お疲れ様でした&ありがとうございました。OCaml Meeting は来年もやる (かも) ということなので、みんな参加するといいと思います。おそらく発表ネタが足りなそうなので何か持っていくと喜ばれそう。

それにしてもイベントの詰め込まれた土日でしたね。天下一カウボーイ大会はどのみち参加しなかったと思うけれど、FLTV は見たかった。

2008-11-11

[] glcaml を cygwin で

glcaml という OpenGL の ocaml binding があったので、cygwin (というか mingw) で遊んでみようと思ったら結構大変でした。メモ。

1. ocaml を mingw 用にビルドする

MinGW-based native Win32 port が公開されていますが、そのインストーラだと ...\Objective Caml というスペースの入ったパスにしかインストールできないっぽいです (嫌がらせだろうか) 。昔これではまったことがあるので、自分でビルドしました *1

mingw 用のビルドの仕方は INSTALL には書いてなくて、README.win32 にあります (嫌がらせだろうか) 。ざっと言うと

  • config/ の中のファイルをコピーする
  • config/Makefile の PREFIX を編集してインストール先を指定する
  • config/Makefile の TK_ROOT を編集して tk をインストールしている位置を指定する
  • make -f Makefile.nt ... する

です。詳細は README.win32 を参照のこと。ぼくは labltk は要らなかったので、config/Makefile の OTHERLIBRARIES から labltk を消してみたところ、tk をインストールしないでビルドできました (正しくビルドできてるかは知らない) 。

2. 環境変数を設定する

こんな感じ。/usr/local/ocaml-3.10.2/bin はインストールしたパスにあわせて適当に。

export PATH=/usr/local/ocaml-3.10.2/bin:$PATH
export OCAMLLIB="`cygpath -w /usr/local/ocaml-3.10.2/lib`

3. SDL をインストールする

http://www.libsdl.org/ から SDL-devel-1.2.13-mingw32.tar.gz を落としてきて、展開して移動するだけ。

$ tar xzf SDL-devel-1.2.13-mingw32.tar.gz
$ cd SDL-1.2.13 /usr/local

4. glcaml をビルドする

install.txt に書いてあるように、makefile を編集して「MAKE=make WIN32=true」の行のコメントをはずします。

以下のように CFLAGS と LDFLAGS を指定して make します。

$ make CFLAGS="-I/usr/local/SDL-1.2.13/include -mno-cygwin" \
  LDFLAGS="-L/usr/local/SDL-1.2.13/lib"

ビルドできたら bin 以下に移動して、SDL.dll をコピーします。なんなら C:\WINDOWS\system32 とかにコピーしといてもいいと思います。

$ cd bin
$ cp /usr/local/SDL-1.2.13/bin/SDL.dll .

サンプルを起動して、窓が出れば OK 。

$ ./lesson09.exe

5. ネイティブコードを出力する

デフォルトだとバイトコードが生成されています。この状態だと、音を鳴らすサンプルを起動すると異常終了すると思います。

$ ./audiosample.exe data/sample.wav
(異常終了の窓)

mixer のコールバック関数がマルチスレッドで呼ばれるのですが、どうもバイトコード実行との相性がよくないようでした。ぼくの環境ではネイティブコードにしたらちゃんと動きました。

ネイティブコードを生成するためには、makefile.inc をいじって all: nc という行を書き足します。

--- makefile.inc
+++ makefile.inc
@@ -18,4 +18,5 @@
 CC=gcc
 SOURCES=$(WIN_SOURCE) $(SDL_SOURCE) $(GL_SOURCE) $(EXAMPLE)
 RESULT=$(BINDIR)/$(MLFILE)
+all: nc
 -include OCamlMakefile

include OCamlMakefile の前に書かないとダメ。書き足したら前と同様に make 。

$ make CFLAGS="-I/usr/local/SDL-1.2.13/include -mno-cygwin" LDFLAGS="-L/usr/local/SDL-1.2.13/lib"

今度は音が鳴りました。

$ ./audiosample.exe data/sample.wav

その他

生成されたコードは -mno-cygwin でビルドしているので、cygwin1.dll がない環境でも動くはず。たぶん。

$ objdump -p audiosample.exe | grep dll
        DLL Name: msvcrt.dll
        DLL Name: msvcrt.dll
        DLL Name: KERNEL32.dll
        DLL Name: SDL.dll

こういうのって何か作ろうと思って環境を整えるんだけど、環境が整ったら満足してしまって何も作らないんですよね。だめだめ。何か作ってから公開しようと思ってたけどやっぱり何も作らなそうなので公開。

*1:あとこのインストーラが勝手に環境変数 OCAMLLIB を設定するので、cygwin の ocaml が動かなくなってはまったことがあるのはぼくだけではあるまい。

2008-04-13

[][] exhaustive な switch

OCaml ではパターンマッチの抜けを警告してくれます。Haskell より OCaml の方が好きな点の 1 つです*1

type t = Foo | Bar | Baz
let f = function Foo -> "foo" | Bar -> "bar"
$ ocamlc pat-test.ml
File "pat-test.ml", line 2, characters 8-44:
Warning P: this pattern-matching is not exhaustive.
Here is an example of a value that is not matched:
Baz

今日気がついたのですが、gcc でも enum に対して同様のチェックをしてくれるようです。

enum t { foo, bar, baz };
char *f(enum t x) {
  switch(x) {
    case foo: return "foo";
    case bar: return "bar";
  }
  return NULL;
}
$ gcc -Wall -c pat-test.c
t.c: In function 'f':
t.c:6: warning: enumeration value 'baz' not handled in switch

ふーんと思った。それだけ。


追記: はてなブックマークより

sshi ghcでも-Wつけるとパターンマッチの抜けを警告してもらえるよ

おお知らなんだ。ありがとうございます。

module PatTest where
data Hoge = Foo | Bar | Baz

f Foo = "foo"
f Bar = "bar"
$ ghc -W -c -o pat-test.o pat-test.hs

pat-test.hs:4:0:
    Warning: Pattern match(es) are non-exhaustive
             In the definition of `f': Patterns not matched: Baz

これがデフォルトでオフなのは、Haskell では (ガードに加えて) non-exhaustive なマッチを意図的に書くことが多いからでしょうかね。無限リストとか。

OCaml でもそういう場合がないことはないけど、そういう場合はちゃんとマッチさせて assert false しようという風習がある気がする。

*1:ガードを使いまくる Haskell のスタイルに合わなさそうなのはわかるんだけど。

2007-12-27

[] OCaml-Nagoya の人たちと飲み会

もう 1 週間も前の話ですが、OCaml-Nagoya の人たちや ocaml.jp の管理人などと飲み会でした。内容が秘密情報なのか公開情報なのか確認しなかったのでどこまで語って良いのかわかりませんが、とりあえず近いうちに日本の OCaml コミュニティが加速するような気がします。日本の OCaml 使いは期待しましょう。

あと今井さん (にわとりの人) は、プログラミング言語より前に定理証明器に出会ったという話とか。ふおおお。