[url=http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/256569]Rocaml[/url] lets you wrtie Ruby extension in Ocaml. It can be a relief to my project, I truely hope. We are using Ocaml with Rails by means of fork or socket and dealing with the format of communication between two sides is just boring.
Now let's have a look at how rocaml works. I'm gonna translate an [url=http://blog.evanweaver.com/articles/2007/03/14/getting-dirty-with-rubyinline]example[/url] in rubyinline to rocaml. Since rubyinline supports basic type transaltion between Ruby and C, the orginal example is forced to declare a lot of complex data type defined in ruby.h by hand:
[code]
require 'rubygems'
require 'inline'
class Check
class << self
inline do |builder|
builder.c_raw "
static VALUE check(int argc, VALUE *argv, VALUE self) {
double x = NUM2DBL(RARRAY(argv[1])->ptr[0]);
double y = NUM2DBL(RARRAY(argv[1])->ptr[1]);
int len = RARRAY(argv[0])->len;
double last_x = NUM2DBL(RARRAY(RARRAY(argv[0])->ptr[len-1])->ptr[0]);
double last_y = NUM2DBL(RARRAY(RARRAY(argv[0])->ptr[len-1])->ptr[1]);
double cur_x, cur_y = 0.0;
int i, c = 0;
for (i = 0; i < len; i++) {
cur_x = NUM2DBL(RARRAY(RARRAY(argv[0])->ptr[i])->ptr[0]);
cur_y = NUM2DBL(RARRAY(RARRAY(argv[0])->ptr[i])->ptr[1]);
if ((((cur_y <= y) && (y < last_y)) ||
((last_y <= y) && (y < cur_y))) &&
(x < (last_x - cur_x) * (y - cur_y) / (last_y - cur_y) + cur_x)) {
c = !c;
}
last_x = cur_x;
last_y = cur_y;
}
if (c == 1) return Qtrue;
return Qfalse;
}
"
end
end
end
[/code]
comparing to Ocaml code:
[code]
let check polygon point =
let len = Array.length polygon in
let last = polygon.(len - 1) in
let result = ref false in
for i = 0 to (len - 1) do
let current = polygon.(i) in
if ((current.(1) <= point.(1) && last.(1) > point.(1)) ||
(last.(1) <= point.(1) && current.(1) > point.(1))) &&
(point.(0) < ((last.(0) -. current.(0)) *.
(point.(1) -. current.(1)) /.
(last.(1) -. current.(1)) +. current.(0)))
then
begin
result := not !result
end;
last.(0) <- current.(0); last.(1) <- current.(1)
done;
!result
open Callback
let _ =
register "Check.check" check[/code]
and then we only have to declare a simple function interface in extconf.rb:
[code]Interface.generate("check") do
def_module("Check") do
fun "check", [ARRAY(ARRAY(FLOAT)), ARRAY(FLOAT)] => BOOL
end
end[/code]
Unfortunately though the ocaml code is more clear than the C one without being polluted by all kinds of type constants, the benchmark shows the rocaml extension is about 5 times slower than the C one. It seems the type conversion is still pricy considering Ocaml code generally should be on the same page with C in terms of speed.
Now let's have a look at how rocaml works. I'm gonna translate an [url=http://blog.evanweaver.com/articles/2007/03/14/getting-dirty-with-rubyinline]example[/url] in rubyinline to rocaml. Since rubyinline supports basic type transaltion between Ruby and C, the orginal example is forced to declare a lot of complex data type defined in ruby.h by hand:
[code]
require 'rubygems'
require 'inline'
class Check
class << self
inline do |builder|
builder.c_raw "
static VALUE check(int argc, VALUE *argv, VALUE self) {
double x = NUM2DBL(RARRAY(argv[1])->ptr[0]);
double y = NUM2DBL(RARRAY(argv[1])->ptr[1]);
int len = RARRAY(argv[0])->len;
double last_x = NUM2DBL(RARRAY(RARRAY(argv[0])->ptr[len-1])->ptr[0]);
double last_y = NUM2DBL(RARRAY(RARRAY(argv[0])->ptr[len-1])->ptr[1]);
double cur_x, cur_y = 0.0;
int i, c = 0;
for (i = 0; i < len; i++) {
cur_x = NUM2DBL(RARRAY(RARRAY(argv[0])->ptr[i])->ptr[0]);
cur_y = NUM2DBL(RARRAY(RARRAY(argv[0])->ptr[i])->ptr[1]);
if ((((cur_y <= y) && (y < last_y)) ||
((last_y <= y) && (y < cur_y))) &&
(x < (last_x - cur_x) * (y - cur_y) / (last_y - cur_y) + cur_x)) {
c = !c;
}
last_x = cur_x;
last_y = cur_y;
}
if (c == 1) return Qtrue;
return Qfalse;
}
"
end
end
end
[/code]
comparing to Ocaml code:
[code]
let check polygon point =
let len = Array.length polygon in
let last = polygon.(len - 1) in
let result = ref false in
for i = 0 to (len - 1) do
let current = polygon.(i) in
if ((current.(1) <= point.(1) && last.(1) > point.(1)) ||
(last.(1) <= point.(1) && current.(1) > point.(1))) &&
(point.(0) < ((last.(0) -. current.(0)) *.
(point.(1) -. current.(1)) /.
(last.(1) -. current.(1)) +. current.(0)))
then
begin
result := not !result
end;
last.(0) <- current.(0); last.(1) <- current.(1)
done;
!result
open Callback
let _ =
register "Check.check" check[/code]
and then we only have to declare a simple function interface in extconf.rb:
[code]Interface.generate("check") do
def_module("Check") do
fun "check", [ARRAY(ARRAY(FLOAT)), ARRAY(FLOAT)] => BOOL
end
end[/code]
Unfortunately though the ocaml code is more clear than the C one without being polluted by all kinds of type constants, the benchmark shows the rocaml extension is about 5 times slower than the C one. It seems the type conversion is still pricy considering Ocaml code generally should be on the same page with C in terms of speed.