Crystal - Ruby風文法を持ったコンパイル型言語
Erlang トレーニング 2013に申し込みを行った。Erlangは全く詳しくないので、トレーニングが非常に楽しみだ。新しいプログラミング言語や、新しいプログラミングパラダイムを学ぶことは楽しい。
さて、プログラミング言語にとって、ぱっと見の見た目は結構重要である。C言語系の見た目であるC++/Java/PHPなどは、C言語を知っていれば違和感を覚えにくい。
今回紹介するプログラミング言語の名前は、Crystalである。Ruby風の文法を持つプログラミング言語だ。つか、ほとんどRuby。アルゼンチンの会社であるmanasの支援を受けて開発されている。
Hello, world!はこちら。
puts "Hello, world!"
どうみてもRubyです(略)。ところが、以下のスクリプトはエラーが出る。
puts 'Hello, world!'
あくまで文法はRuby風、というわけ。
Crystalの実行速度
RPythonで書かれたRuby処理系であるTopazというものを以前のエントリで紹介した。そこで、MRIとTopazとの速度比較を行う一例として、セクシー素数を求めるコードを紹介した。引用すると、以下のようなコードである(Crystalのcommit 006fc13cで動作するように一部修正)。
def is_prime? n
(2...n).all? { |i| n % i != 0 }
end
def sexy_primes n
(9..n).map do |i|
[i - 6, i]
end.select do |i|
i.all? { |j| is_prime? j }
end
end
sexy_primes 100_000
上記セクシー素数を求めるコードを、手元のMacbook ProでRuby 2.0.0-p247とCrystalとで実行してみる。Crystalでは1.61秒。Ruby 2.0.0-p0では59.57秒。すごい速度差。それにはワケがあるわけで。
インストール方法
Ruby 1.9.3が入っているMac環境では、以下のようにしてCrystalを動作させることができる。2013年8月28日現在、いまだ.rvmrcを使っているのでrvm使いには警告が出る。また、Ruby 2.0.0-p247では動作しなかった。LLVMは3.3。
Linux環境では、libllvmが入るようなパッケージを入れればOK。
> brew install llvm --shared > git clone git://github.com/manastech/crystal.git > cd crystal > bundle > bin/crystal -e 'puts "Outsourcing!"' # ワンライナー > bin/crystal -run hello.cr # スクリプト実行
bin/crystalで実行してみると分かるが、体感として実行速度が遅いことに気づく。なぜだろうか。
Crystalの仕組み
LLVMをインストールしていたのでおわかりの方は多いと思うが、Crystalは、Ruby風の文法を解釈し、LLVM IRを生成し、それをネイティブコード化して実行している。ワンライナーの実行速度が遅いのは、そのせいだ。
よって、以下のように実行ファイルをコンパイルしておけば、動作速度は速くなる。
> bin/crystal hello.cr > ./hello
生成されたLLVM IRをのぞき見ることができる。Hello, world!だとこんな感じ。
> bin/crystal -O3 -l1 hello.cr
; ModuleID = 'Crystal'
(中略)
@str2 = private constant [18 x i8] c"\0D\00\00\00Hello, world!\00"
define i1 @__crystal_main(i32 %argc, i8** %argv) {
alloca:
br label %const
const: ; preds = %alloca
br label %"GC::objects_size"
entry: ; preds = %"const_MatchData::EMPTY"
%0 = load %MatchData** @"MatchData::EMPTY"
store %MatchData* %0, %MatchData** @"$~"
%1 = call i1 @"*puts:Nil"(%String.0* bitcast ([18 x i8]* @str2 to %String.0*))
ret i1 %1
Crystalが目指すところ
Crystalは、ライブラリ経由でC言語の関数を呼び出しやすいように設計されている。例えばこんな感じで、sqlite3_libversion()関数を呼び出せる。
lib LibSQLite3("sqlite3")
fun sqlite3_libversion : Char*
end
つまり、目指すところはC言語の代替物ということらしい。
例えば、samplesディレクトリにはHTTPサーバの例がある。
#!/usr/bin/env bin/crystal -run
require "socket"
server = TCPServer.new(8080)
puts "Listening on http://0.0.0.0:8080"
while true
sock = server.accept
while str = sock.gets
if str == "\r\n"
sock.print "HTTP/1.1 200 OK\r\n"
sock.print "Content-Type: text/plain\r\n"
sock.print "Content-Length: 12\r\n"
sock.print "\r\n"
sock.print "Hello world!"
sock.flush
end
end
end
Crystalの適用領域として、HTTPサーバのようにそれなりにチューンしたいけど、Rubyの記述力も欲しいよね、といったニーズに特化しているものと予想する。
Crystalは現在セルフホスティング(CrystalでCrystalコンパイラを記述する)を目指しているようである。現在はruby-llvmを使っているはず。セルフホスティングされて、仕様も安定してきたら、それなりに高速なグルー言語としてお試ししてみたい。現在はTimeすらないし、 正規表現オブジェクトもない。正規表現オブジェクトはあった。facebookでツッコミを受けました。PCRE利用のようです。
