たらい回し関数
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')";;
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
#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;;



プログラミング in OCaml ~関数型プログラミングの基礎からGUI構築まで~