First taste of rocaml

Rocaml 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 example 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:
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


comparing to Ocaml 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

and then we only have to declare a simple function interface in extconf.rb:

Interface.generate("check") do
  def_module("Check") do
    fun "check", [ARRAY(ARRAY(FLOAT)), ARRAY(FLOAT)] => BOOL
  end
end


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.

你可能感兴趣的:(c,C#,haskell,perl,Ruby)