たらい回し関数

jrubyのたらい回し関数のエントリみてたらClojureでもやってみたくなった。

Clojure 1.0.0-
user=> (defn tak [x y z] 
      (if (>= y x) 
      z 
      (tak (tak (- x 1) y z) (tak (- y 1) z x) (tak (- z 1) x y))))
#'user/tak
user=> (time (dotimes [_ 100] (tak 24 16 8)))
"Elapsed time: 27580.504 msecs"
nil

ついでにOCamlでも

let rec tak x y z =
  if y >= x then z
  else tak (tak (x-1) y z) (tak (y-1) z x) (tak (z-1) x y)
;;

for a = 1 to 100 do
  ignore(tak 24 16 8)
done
;;

まずはバイトコードで。

$ ocamlc tak.ml -o tak.exe
$ time ./tak.exe 

real    0m10.777s
user    0m10.692s
sys     0m0.033s

ネイティブコードにコンパイルすると

$ ocamlopt tak.ml -o tak_opt.exe
$time ./tak_opt.exe 

real    0m1.130s
user    0m1.119s
sys     0m0.006s

結構はやい。

そういえばMooseでLispはたらい回し関数はしるくらいまではやっとこうと思いつつ止まってしまっていたのに今気づいた。

駱駝使いw

perlと言えば駱駝、OCamlと言えば駱駝。つまり両頭使いは必然の流れですな。

perl4camlを使うとocamlでperlのコードを取り込める。

#require "perl";;
open Perl;;
eval "use Net::Twitter";;
eval "Net::Twitter->new({username => 'ur', password => 'pw'})->update('from perl4caml')";;

from perl4caml

CPANの膨大な資産が使えるのは魅力。

ocamlでtwitterのタイムラインを取得

ocurl入れてocamlコマンドからロードしようとすると

# #load "curl.cma";;
Error: The external function `helper_curl_version' is not available

といってエラーがでる。libcurl-helper.aを一緒にしないといけないっぽいが。

仕方ないのでocamlcでコンパイルすることにした。

Curl.global_init Curl.CURLINIT_GLOBALALL;
let connection = new Curl.handle in
connection#set_userpwd "user:password";
connection#set_url "http://twitter.com/statuses/friends_timeline.xml";
connection#perform
;;

をmain.mlで保存して

$ ocamlc -I . -ccopt -L. curl.cma main.ml

できたa.outを実行するとうまくうごく。

あとはutf8の処理とxmlの処理。

mac osxのswigでOCamlを使えるようにする

オプションで指定する。

sudo port install swig +ocaml

でも、なんかエラーが出てて、いまのとこうまいこと使えてない。

OCamlのべき乗

floatしかべき乗の演算子がないのは何故?

# 2.0 ** 3.0;;
- : float = 8.

int

# 2 ** 3;;
Characters 0-1:
  2 ** 3;;
  ^
Error: This expression has type int but is here used with type float

arcsinのテーラー展開でπをもとめる(ocamlで)

let rec power m = function
    0 -> 1
  | n -> m * power m (n-1)
;;

let rec factorial = function
    0 -> 1
  | n -> n * factorial (n-1)
;;

let rec calc_pi = function
    0 -> 3.0
  | n -> (float_of_int (3 * factorial(2*n))) /.
 (float_of_int ((power 2 (4*n)) * (power (factorial n) 2) * (2*n+1))) +. calc_pi (n-1)
;;

これだとcalc_pi 6ぐらいでneg_infinityになってしまう。あと型で結構つまづく。

普通に求めるヤツ

let mc () =
let x = Random.float 1.0 in
let y = Random.float 1.0 in
if sqrt ((x ** 2.0) +. (y ** 2.0)) <= 1.0 then 1
else 0
;;

let rec count n res = match n with
  0 -> res
| _ -> count (n-1) (res + mc())
;;

let calc_pi n =
  let res = count n 0 in
  (float_of_int res)*.4.0 /. (float_of_int n)
;;

OCamlでbz2

どう書く?org : データの圧縮と展開

#require "bz2";;

let compress str =  Bz2.compress str 0 (String.length str);;
let uncompress str =  Bz2.uncompress str 0 (String.length str);;

let _ = uncompress (compress "test");;

参考

camlzipってのもあるんだが、ちょっと使いにくい感じがした(require出来ないし)

OCamlでfork

どう書くの外部の実行ファイルを呼び出しって問題を解く。

ブロックする版は

#load "unix.cma";;
Unix.system "/bin/sleep 3";;
print_string "waited\n";;

でいいんでしょ。

で、ブロックしない版をこんな感じで書いたら、

let pid = Unix.fork () in match pid with
     0 -> Unix.system "/bin/sleep 3"; print_string "waited\n"
   | _ -> print_string "not wait\n"
;;

warningがでる。

Warning S: this expression should have type unit.

よくわからなくて気持ち悪い。

追記090909

ignoreを使えばよいとはてブで教えてもらった。

# ignore;;
- : 'a -> unit = <fun>

unitを返す

let pid = Unix.fork () in match pid with
     0 -> ignore(Unix.system "/bin/sleep 3"); print_string "waited\n"
   | _ -> print_string "not wait\n"
;;

OCamlのファイルアクセス

openfileとかopen_outとかopen_out_genとか色々あるので混乱する。

let file = Sys.argv.(1) in 
let f = try open_out_gen [Open_wronly; Open_creat; Open_trunc; Open_text] 0o600 file
with Sys_error msg -> failwith ("Couldn't write to " ^ msg) in 
output_string f "OCaml\n";close_out f;;

どう書く?org:ACLの制御

ocamlcで吐いたバイトコード

Standalone Executables

実行ファイルの一行目に

#!/usr/local/bin/ocamlrun

って書いてあるで、って書いてあったので確かめた。

ほう。