Language
Imperative features (1.5)
配列(Array)
再帰以外の繰り返し
Labels(2.1)
Optional arguments (2.1.2)
Classes and objects (3.1)
Class定義
Instanceを作成
メソッドへのアクセス
Reference to self (3.2)
Initializers (3.3)
Inheritance (3.7)
Language extensions (7)
Local Modules
structureとsignatureとfunctor
Libraries
The core libraries
Pervasives Module
入出力
文字列処理
The standard libraries
Array Module
Arg Module
Char Module
Filename Module
Genlex Module
Hashtbl Module
Lazy Module
Lexing Module
List Module
Printf Module
Queue Module
Map Module
Marshal Module
Obj Module
Set Module
Stream Module
String Module
Sys Module
Str library
Str Module
The threads library
Thread Module
Mutex Module
Dbm library
Dbm Module
Graphic library
Graphics Module
Bigarray library
Bigarray Module
Unix library
Unix Module
Labltk library
Tk Module
その他
コンパイル
ocamlc
ocamlmktop
ocamldebug
プロファイリング
逆アセンブル
Cの関数を呼ぶ
Ocamlでscript
lablgtk
lablgtk2
ocamlyacc / ocamllex
Standard MLとの比較
Emacs Lispたち
Ocamlのインストール
趣味の世界
ツール
ocamlweb
ocamldoc
リンク
CWNメモ
メモ
他のMLを使った感想
サンプル
配列(Array)
Array module がある。
配列は [| と |] で囲んで表す。要素間は ; で区切る。添字はzero origin.
e.g.)
#let a = [| 1;2;3;4;5 |];;
Array Module再帰以外の繰り返し
while [condition] do ... done;;
for [variable] = [initial_value] to [finish_value] do ... done;;
breakは例外処理でできる。 try ... with ** -> ..
仮引数にラベルを付けることができる。
関数の仮引数の前に ~ を付ける。
インターフェイスと関数内部で異なる変数名を用いることができる。
e.g.)
#let f ~x:x1 ~y:y1 = x1 - y1;;
val f : x:int -> y:int -> int = <fun>
関数適用時に明確にラベルを用いるときは次のように書く。
e.g.)
#f ~x:3 ~y:2;;
- : int = 1Optional arguments(2.1.2)
引数をオプションにできる。
?([variable_name] = [default_value])と書くとオプション化される。
束縛するときは ~ を使う(Labelなので)
例
option.ml
Classがある。moduleによく似ているが type..による型定義がない のと、継承、インスタンス化(new ...)があることなど(オブジェクト指向なので、 オブジェクトの状態を規定する)がことなる。
オブジェクト生成時に初期値を与えるときは、classの定義に おいてobjectを返す関数を定義する。
e.g.)
class tak = fun init ->
object
val mutable money = init
method earn = fun value -> money <- money + value
end;;Class定義
class [class_name] =
object
val ... [definition_of_member_variable]
method ... [definition_of_method]
end;;
valでメンバー変数を定義、methodでメソッドを定義する。
内部でparametalizeされた型を扱える。# class ['a] hoge (x : 'a) = object method print = print_string "new hoge" val a = x method get_a = a end;; class ['a] hoge : 'a -> object method get_a : 'a method print : unit val a : 'a end # let a = new hoge 1;; val a : int hoge = <obj> # a#get_a;; - : int = 1 # let a = fun x -> x#print 1 2;; val a : < print : int -> int -> 'a; .. > -> 'a = <fun> (* 部分型を伴う型推論 *)Instanceを作成
let [variable_name] = new [class_name]メソッドへのアクセス
[class name]#[method name]
仮想関数が一つでもあるクラスはclass virtual [classname]のようにvirtualを付けて 定義しなければならない。class type
moduleにmodule typeがあるように、classにもclass typeがある。例
# class a = object method hello = "tak\n" end;; class a : object method hello : string end # class type at = object method hello : string end;; class type at = object method hello : string end # class new_a = (a : at);; class new_a : at # (new new_a)#hello;; - : string = "tak\n"おまけ)
メンバー変数への外からの直接のアクセスはできない。
オブジェクトが内部で自分自身を参照するには、 class定義のobjectの後に[variable name]を挿入する。その変数名に自分自身が束縛される。
おまけ)
自分自身(self)のsかselfを使いたいらしい。
クラス定義におけるlet文はobject生成前に評価される。
後に評価して欲しいものはInitializerというキーワードの後に記述する。
Initializerの後は順序処理される。
中略)
多重継承・仮想関数は、暇なときに。
class定義の中でinheritに続けて継承するクラスを書く。
Coreのスコープ内でModuleを定義できる。Setなんかをちょっと道具として使う場合に便利。
サンプル local_module.ml
あれ!? 超dependent SetのMakeに引数Stringを渡して適用した時のt型!? escape_abstract.ml
> ocamlopt.opt -i escape_abstract.ml -o escape_abstract val friends_list : string list val escape_abstract_data : unit -> Set.Make(String).t
MLではモジュールシステム自体が型(signature)を持つ。structureは型、値、関数の定義をおく。 signatureは各structureに対する型のようなもので、各メンバの型を指定する。このsignatureに書かれた名前が 外部のモジュールから参照可能な名前である。
functorは structureからstructureへの関数のようなもの。structureの中で(未定義の)型、関数等を抽象化 出来る。functorの定義自体はstruct Foo (Something : Compareble) = (* SomethingはCompareble signatureを満たす型 *) struct let compare x y = Something.compare x y ... endのようにstructからstructへの関数として書く (引数にはsignatureをつける) かstruct Foo = functor (Something : Compareble) -> struct let compare x y = Something.compare x y ... endのように、core言語のfunのようにfunctorキーワードを使ってfunctorを記述することも できる。このstructureに対するsignatureはfunctor (Something : Compareble) -> sig val compare x y: 'a -> 'a -> int endのようにfuntorキーワードで表現される。文法
module [structure name] =
struct
[implementation]
end
module type [signature_name] =
sig
[definition_of_interface]
end
module [object_name] =
([structure_name] : [signature name])structure
structureは、お互いに関連した定義を集めたものである。structureの中に 入れることで、名前の衝突を防ぐことができる。また、引数にstructureを与えて、 structureを返す「関数」のような機能をもつfunctorを定義することもできる。signature
signatureは、structureのインターフェイスである。ここに公開するものを 書いておく。公開されないものは外からは見えない。
# module type A = functor (Arg : sig type t end) -> sig type t = Arg.t end;;
module type A = functor (Arg : sig type t end) -> sig type t = Arg.t end
functor typeもあり。with による signature の制限
例として次のようなコード (ocamlインタプリタ上でのセッション) を考える。Set.S では 型 elt は type elt のように opaque な型として宣言されている。集合の 要素の型を抽象化しているので要素の型を指定できないのは当たり前である。そして、 (Set.Make(String) : Set.S) のように普通に signatureで制限してしまうと、Set.Make(String) の elt 型は opaque な型となり隠蔽される。実際、StringSet.t は string 型であるのだが、 それは外から見えないので add "mamewo" emtpy とすると型エラーが起こっている。
# module StringSet = (Set.Make(String) : Set.S);; module StringSet : Set.S # open StringSet;; # add "mamewo" empty;; Characters 4-12: add "mamewo" empty;; ^^^^^^^^ This expression has type string but is here used with type StringSet.elt
でも、それでは、集合に要素をいれることなんてできない!! こんなときに with による signature の制限が使える。これを使うことで、 signature内で opaque に宣言された型が manifest な型として(指定した型と互換性のある型) 使用できる。with によって、外から elt という型を string と等価な型にしてほしいと指定 することができ、無事に string 型の要素を集合に付け加えることができる。
# module StringSet = (Set.Make(String) : Set.S with type elt = string);; module StringSet : sig type elt = string and t val empty : t val is_empty : t -> bool val mem : elt -> t -> bool (* ... *) end # open StringSet;; # add "mamewo" empty;; - : StringSet.t = <abstr> # elements (add "mamewo" empty);; - : StringSet.elt list = ["mamewo"]
これは .mli ファイルを書くときに便利。たとえば、実装で、 上のような StringSet を定義して、すべての関数を公開する場合 Set.S をそのまま適用 しようと安直に考えると opaque な型になりうまくいかない。しかし、with を 用いて要素の型を指定することによって、 Set.S を有効に利用できる。
このモジュールは自動的にopenされる。
output,input,string_of_int,int_of_string,print_newline( ^ ),( + ),( - )...(数値演算)
等が定義されている。
また、
stdin,stdout,stderr(input-output channels)や、numbers, booleans, string, exception, references, lists, arrays...等の型が定義されている。
入出力
標準入出力
標準入出力に割り当てられているout_channel,in_channelの変数名は
stdin 標準入力
stdout 標準出力
stderr 標準エラー出力
である。
ファイル入出力
output: out_channel -> string -> int (position) -> int (length) -> unit
out_channelにstring上の位置positionから長さlengthだ け出力する。返値は実際に書き込んだ長さ。
input: in_channel -> string -> int (position) -> int (length) -> int
input_channelからstring上の位置positionにlength byteだけ 入力する。返値は実際に読み込んだ長さ。0ならばファイルの終りを意味する。 実装に よっては length byte 読み込む前に関数が返る。返り値が実際に読み込んだバイト数 を表す。丁度 length byte 読むには length byteだけ読めるまで input を呼ぶのを繰 り返すか、 really_input を使う。
really_input: in_channel -> string -> int (position) -> int (length) -> int
丁度 length byte 読み込む。読み込む前にファイルの終りに達したら End_of_file 例外が投げられる。
例
input_all.ml
input_line : in_channel -> string
一行読み込み。最後の改行文字はなくなる 最後まで読んだ時は End_of_file 例外を 投げる
print_string : string -> unit
文字列を標準出力に表示する
print_newline : unit -> unit
改行を入れる。
flush : out_channel -> unit
バッファをフラッシュする。
文字列処理
string_of_int : int -> string
int_of_string : string -> int
int <-> stringの変換。stringは整数を表現したもの。 16進表示でもよい。
^ : string -> string -> string
中置演算子。文字列をつなげる
ignore : 'a -> unit
値を捨てる。逐次実行で返り値がunitで無いものがあるとコンパイラが警告を だす。この警告を避けるためのもの。
at_exit : (unit -> unit) -> unit = <fun>
終了時に行なう処理を登録する。複数登録できて、後に登録したものが先に呼び出される。
サンプルプログラム (at_exit.ml)
Array.create int -> 'a -> 'a array
配列を作る。initial valueの型で配列の型が決定される。
Array.length 'a array -> int
配列長
Array.set 'a array -> int -> 'a -> unit
代入
Array.get 'a array -> int -> 'a
参照
Sys.argv.(1)のように括弧を用いてアクセスすることもできる。# let a = [| 1;2;3;4;5 |];; val a : int array = [|1; 2; 3; 4; 5|] # a.(3);; - : int = 4 # a.(1) <- 100;; - : unit = () # a;; - : int array = [|1; 100; 3; 4; 5|]
コマンドライン引数、オプションの処理を行う。Sys.argv.(0)は対象外 (プログラム名) -help でusageを表示するような 機能が埋め込まれている。
Arg.parse (string * Arg.spec * string) list -> (string -> unit) -> string -> unit
第一引数はオプションの設定を記述しているリスト。要素の一番めはオプション文字列("-"を含む)、 二番めは動作、三番めは -help で表示される説明文字列である。第二引数はオプション以外の (ファイル名などの)コマンド引数を処理する関数、第三引数は -help オプションをつけた 時に表示される説明の一番最初に表示される文字列を指定する ("usage: cmd [options] [files]" のようにコマンドラインの文法とか)
Arg.usage (string * Arg.spec * string) list -> string -> unit
-helpオプション指定時に表示されるような使用方法の表示をする。第二引数の stringは使用方法の最初の行の文字列例
arg_test.ml
参考 getopt
pcc.ml
オプションを複数回指定すると指定した分だけ呼ばれる。perl の Getopt::Std では複数回数同じオプションを指定すると最後のオプションの値で上書きされてしまう (涙)
Char.uppercase : char -> char
Char.lowercase : char -> char
大文字<->小文字の変換
Char.code : char -> int
文字からASCIIコードに変換 (0 〜 255)
Char.chr : int -> char
ASCIIコードから文字に変換
パスや拡張子を扱う文字列処理をする。
Filename.check_suffix : string -> string -> bool
第一引数の文字列が第二引数で指定されるsuffixにあうかをチェックする。あえばtrue。 別に "." が 意味をもつわけではなく、第一引数の文字列の末尾が suffix にあうか否かをチェックしている。
例
サンプル check_suffix.ml
Filename.chop_extension : string -> string
ファイル名から拡張子をとった文字列を返す。"." もとる。
使用例
サンプルプログラム file.ml
Strを使って模倣してみた fileregexp.ml
たとえばmlのファイル名から、そのファイルが定義するモジュール名を求める basename.ml (basenameのサンプル)
お手軽に字句解析を行なうことができる。キーワードを設定できる。
type token = | Kwd of string | Ident of string | Int of int | Float of float | String of string | Char of char
キーワード、識別子、整数、実数、文字列、文字が扱える。文字列は""で括られた もので、文字は''で括られた一文字。(* *) で括られるとコメント!!
Genlex.make_lexer : string list -> char Stream.t -> token Stream.t
字句解析関数を生成する。引数の文字列リストはキーワードを渡す。
例# let st = Genlex.make_lexer [] (Stream.of_channel stdin);; val st : Genlex.token Stream.t = <abstr> # Stream.next st;; (* takashi *) 12 - : Genlex.token = Genlex.Int 12
ハッシュ。Hashtbl,Map,Setはfunctorとして定義されている。Hashtblはハッシュ関数と 等価関数(equal)を必要とし、Map,Setは比較関数を必要とする。どれもMakeがfunctorである。 ハッシュ関数は byterun/hash.c の hash_aux関数で具体的に定義されている。オブジェクトのタグを 見て型にふさわしいハッシュ関数をつかってハッシュ値を返す。この関数はocamlからは多相関数 Hashtbl.hashで使える。
値の型を制限する
create時が適当かと思いますが。
サンプル(restrictHashValueType.ml)
サンプル
hashSample.ml
実行結果> ocamlopt hashSample.ml -o hashSampleメモ
> ./hashSample
okui
wo
Fatal error: exception Not_found
Is_young,Is_atom,Is_in_heap..? Tag_valはタグとりだし
ハッシュ関数
accu = accu * α + new (α = 19 or 65599)
タグの種類(一部?)
String_tab,Double_tag,Double_array_tag,Abstract_tag,Infox_tag,Object_tag,Custom_tag
builtin_cprimにプリミティブ関数が並ぶ。 hash_univ_paramも登録されている。names_of_builtin_cprimにそれらの関数の名前が登録されている。byterun/dynlink.cで名前と一致する関数を取り出している。(54行目近辺)
遅延評価のためのモジュール。Lazy.statusはDelayed of (unit -> 'a) (評価されていない) Value of 'a (評価された) Exception of exn の3つ。Lazy.status へのリファレンスをforceで評価する。DelayedはValueに変わり値のメモが取られる。
サンプル(講義を自分で復習してみただけだったりする)
libSequence.ml (Lazyモジュールを用いたシーケンス)
useSequence.ml (使い方 素数表とか)
ocamlyacc, ocamllex を使ってパーザー、レキサーをつくった時に使用できるレキサー。
lexbuf の pos_cnum というフィールドのみ自動的に値が更新され、他は更新されない。 行番号情報を管理したい時は *.mll ファイルに管理するようなコードを記述しなければならない。 改行に出会った時に以下の関数を呼び出すとか。Lexing.lexeme lexbuf -> string
let newline lexbuf = lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_lnum = lexbuf.lex_curr_p.pos_lnum + 1 } let reset_lexer lexbuf = lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_lnum = 1 } let nl = '\013' '\010' | '\010' rule token = parse nl { newline lexbuf; token lexbuf } | ...
正規表現にマッチした文字列を返す
Lexing.lexeme_char lexbuf -> int -> char
マッチした文字列のi番目の文字を返す
Lexing.lexeme_start lexbuf -> int
マッチした文字列のストリーム上での開始位置
Lexing.lexeme_end lexbuf -> int
マッチした文字列のストリーム上での終了位置
ocamllexで生成されたlexerはlexbufという名前のバッファを持つ。(引数名がlexbuf)サンプル
実数の簡単なパース lexfloat.tar.gz
List.fold_left ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
List.fold_right ('a -> 'b -> 'b) -> 'a list -> 'b -> 'b
畳み込み。leftは(f an (f an-1 (... (f seed a1)...)))で末尾再帰であり,rightは (f a1 (f a2 (... (f an seed)...)))で、末尾再帰でない。
例)# List.fold_left (fun x y -> x ^ y) "" ["takashi"; "masuyama"; "mamewo"];; - : string = "takashimasuyamamamewo" # List.fold_right (fun x y -> x ^ y) ["takashi"; "masuyama"; "mamewo"] "";; - : string = "takashimasuyamamamewo"
List.combine 'a list -> 'b list -> ('a * 'b) list = <fun>
aの要素とbの要素を順番に対応づけてペアにしたリストを返す。zipとか言ったような言わなかったような。
Printf.printf ('a, out_channel, unit) format -> 'a
formatはCに似ている
%s 文字列
%d 10進数
%x 16進数
%o 8進数
%f 浮動小数点数
formatから、第二引数以降の型が推論されている!!
Printf.sprintf ('a, unit, string) format -> 'a
Printf.printfのStringバージョン。フォーマットにしたがった文字列を返す。
副作用を伴うキュー。サンプル
queue_test.ml
全順序がついたキーである値を連想するときに使う。以下 Map.Make の結果の module についての解説。
add : Map.S.key -> 'a -> 'a Map.S.t -> 'a Map.S.t
map にキーと値を登録する。先に同じキーに対して登録されていたものは失われる。サンプル
あとから add したものが先にあったものを上書きする maptest.ml
小さい MultiMap を作ってみた。ただ値の部分をリストにするだけ。 multimap.ml
Map同士の結合を定義してみた。確か union じゃなくて何か名前がある。customizedMap.ml
値を入出力する。入力する値の型は推論できないので、プログラマが指定する。 Pervasives.input_value,Pervasives.output_valueはこのMarshalモジュールを使用して いる。
例)# let f = open_out "hoge";; val f : out_channel = <abstr> # output_value f "hoge";; - : unit = () # output_value f (1,2,3);; - : unit = () # close_out f;; - : unit = () # let f = open_in "hoge";; val f : in_channel = <abstr> # (input_value f : string );; - : string = "hoge" # (input_value f : int*int*int );; - : int * int * int = 1, 2, 3input_valueの返り値の型を指定してやらなければならない。
例
save_hash.ml
(string, bool) Hashtbl.t 型の値を保存
Not for casual userとマニュアルには書いてあるので、積極的に 使うものではないらしい。値の内部表現に関する演算。
Obj.tag : t -> int
Obj.is_int : t -> bool
Obj.obj : t -> 'a
興味本位な例)# let my_pen_name = "mamewotoko";; val my_pen_name : string = "mamewotoko" # (Obj.tag (Toploop.getvalue "my_pen_name")) == Obj.string_tag ;; - : bool = true # (Obj.obj (Toploop.getvalue "my_pen_name"));; - : '_a = <poly> # ((Obj.obj (Toploop.getvalue "my_pen_name")):string);; - : string = "mamewotoko" # ((Obj.obj (Toploop.getvalue "my_pen_name")):int);; - : int = 538436204型のチェックはしなければならない。
むっちゃ使える集合ライブラリ。内部的にはバランスした二分木で実装されている。 Set.Make functor でモジュールを作成する。この functor に与えるべきものは、 比較できる型 t とその型に対する比較関数 compare である。 compare については 型多相に定義されているものが Pervasives モジュールにあるのでそれをそのまま 渡してしまってよい。(use_functor_now.ml 参照)
Set.diff: t -> t -> t
Set.diff s1 s2 は s1 から s1 と s2 の intersection を取り除いた 集合を返す。集合の引き算。s1 になくて、s2 にある要素は結果に関係しない。
例サンプル
# module StringSet = Set.Make(String);; module StringSet : sig (* ... *) # let s1 = List.fold_right StringSet.add ["tak"; "mamewo"; "masu"] StringSet.empty;; val s1 : StringSet.t = <abstr> # let s2 = List.fold_right StringSet.add ["tak"; "aki"; "mamewo"; "mango"] StringSet.empty;; val s2 : StringSet.t = <abstr> # StringSet.elements (StringSet.diff s1 s2);; - : StringSet.elt list = ["masu"] (* s2からs1をひく。s1にあるけど、s2にない "masu" はあってもなくても*) # StringSet.elements (StringSet.diff s2 s1);; - : StringSet.elt list = ["aki"; "mango"]
set_diff.mlサンプル
touple_set.ml
use_functor_now.ml functorの引数にモジュール名ではなく struct .. end を書く。
順序を持ったデータの集まりで、先頭から順にアクセスすることを許す。ストリームの 関数は副作用を持つものと、値を返すだけで、副作用を持たないものがあるので、 注意が必要。ストリームは空かも知れないし、値を持つかも知れない。値を持つか、持た ないかはocamlでは'a option型で表現する。Some of 'a (値を持つ) | None (値を持たない)
Stream.from: (int -> 'a option) -> 'a t
Stream.of_list: 'a list -> 'a t
Stream.of_string: string -> char t
Stream.of_channel: in_channel -> char t
ストリームの構築。
Stream.iter: ('a -> unit) -> 'a t -> unit
ストリーム全体に関数を適用。
Stream.next: 'a t -> 'a
ストリームの最初の要素を返す。最初の要素は削除される。
Stream.count: 'a t -> int
捨てられた要素の数
Stream.npeek: int -> 'a t -> 'a list
最初のn個の要素をリストにして返す。n個未満の時はそれらをリストにする。
stringも"zero origin"。
stringは ""で囲む。
charは ' 'で囲む。
String.length [string]
stringのために確保されている長さを返す。
String.get [string] [position]
String.set [string] [position] [char]
stringのposition番目の文字をcharに置き換える。
String.create [length]
長さlengthの文字列を作る。
場所を確保するだけで、内容は不定。
String.make [length] [initial_char]
initial_charの長さlengthの連を作る。
String.copy [string]
文字列をそのまま返す
String.concat [string] [string_list]
文字列と文字列のリストをとる。
文字列のリストの要素の間に第一引数の文字列を連結した文字列を返す。
String.uppercase string -> string
String.lowercase string -> string
文字列全体にCharのuppercase,lowercase (それぞれ、小文字、大文字への変換) をmapする。
String.escaped string -> string
特殊文字を \ でエスケープした文字列を返すメモ
String s の n 番目の文字は s.[n] のようにして参照できる。配列の場合は () を使う ことに注意サンプル
[] で参照.... StringGetNotation.ml
Sys.argv
コマンドライン引数文字列
Sys.command string
Sys.file_exists string -> bool
Sys.remove string -> unit
Sys.rename string -> unit
Sys.os_type
OS情報を示す変数。
Sys.time unit -> float
Sys.chdir string -> unit
作業ディレクトリの変更
Sys.getcwd unit -> string
作業ディレクトリ名
Sys.getenv string -> string
環境変数の取得
例
getenv.ml
Sys.word_size
Sys.max_string_length
Sys.max_array_length
Str moduleはCで実装されている (otherlibs/str/strstubs.c) 正規表現を 使える。ocamlインタプリタ上で使用するには #load "str.cma";; を実行する。
Str.regexp: string -> regexp
正規表現をコンパイルする。
Str.regexp_case_fold: string -> regexp
大文字、小文字の差を無視するように正規表現をコンパイルする。
Str.string_match: regexp -> string -> int -> bool
正規表現によるパターンマッチを行う。マッチに成功したか?(bool)が返る。int はマッチを開始する位置。
Str.matched_group: int -> string -> string
最後に行ったマッチでN番目のグループにマッチした部分文字列を返す。ここで、 stringはその最後に行ったマッチと同じ文字列にしなければならない。これはプログラマーの 責任。位置を覚えているらしい。
Str.string_before: string -> int -> string
Str.string_after: string -> int -> string
Str.match_beginning: unit -> int
マッチした開始位置
Str.match_end: unit -> int
マッチした終了位置
Str.split: regexp -> string -> string list
regexp は区切り文字を正規表現で表したものである。区切り文字で文字を区切って結果を文字列 リストにして返す。
例) split_by_colon.mlグループにマッチした文字列を取り出す例
# #load "str.cma";; # let r = Str.regexp "mamewo\\(.+\\)$";; val r : Str.regexp = <abstr> # Str.string_match r "mamewotoko" 0;; - : bool = true # Str.matched_group 1 "mamewotoko";; - : string = "toko" (* matched_group には直前のマッチに使った文字列を渡すべき。 違う文字列を渡すとどうなるか観察してみる *) # Str.matched_group 1 "mamewohogegheo";; - : string = "hoge" (* マッチした位置を保存しているのかな? *)
正規表現
. 改行以外の任意の一文字にマッチ ^ 文頭にマッチ $ 文末にマッチ [] 文字集合 * 直前のパターンの0回以上の繰り返し + 直前のパターンの1回以上の繰り返し ? 直前のパターンの1回または0回のマッチ \| (中置)選択 \(\) グループ化
例
.dependの依存元 (依存するほう?) を表示 inverseDepend.ml
Bが入力。 A depend on B なるAを出力
Str.string_matchは指定された位置からマッチを開始する。test.ml
文字列ではグループ化はbackslash( \ ) をエスケープして "\\(...\\)" と表現するよ strtest.ml
\| ってあんまり使わないけど、使いたくなることはある。grp.ml
\(...\)? のようなマッチで、グループにマッチする文字列がなかった場合に、 あとで、 matched_group でこのグループにマッチした文字列を取り出すと Not_found 例外が返る。 regexp_question.ml
EUCで日本語をマッチ。 teacup.ml
Thread.t型がスレッドハンドラ型
Thread.create: ('a -> 'b) -> 'a -> t
スレッド作成。引数には実行する関数とその引数を渡す。第一引数の関数の 返り値は捨てられる (discarded) ので、親からその返り値は直接は参照できない。 なにか外に値を返すなら、リファレンスに値を書き込むようにする。let future f x = (* 結果の書き込み先をローカルにする。 *) let result = ref [] in let t = Thread.create (fun x -> result := (f x)::!result) x in (t, result) ;; (* ううむ、なにか違う名前だったような.... *) let attach (t, result) = begin Thread.join t; match !result with hd::[] -> hd | _ -> failwith "???" end ;;サンプル
mlThread.ml
return_thread_value.ml
configure -with-pthread で configure を実行して、make world && make install すると、バイト コードだけでなく、ネイティブでもスレッドを使用できる。 つまり /usr/local/lib/ocaml/threas/threads.cmxa が作成される。
排他ロック。
Mutex.create: unit -> t
ロック作成。Mutex.t がロックの型
Mutex.lock: t -> unit
ロックを獲得する。獲得できなかったら他のスレッドがロックを解放 (Mutex.unlock) するまで待つ。
Mutex.try_lock: t -> bool
ロックの獲得を試みて成功したら獲得してtrueを返す。失敗しても解放を待たずに false を返す。
Mutex.unlock: t -> unit
ロックを解放する。他のロックを獲得しようとしているスレッドが(あれば)再開する。サンプル
関数を局所的に宣言できるので、ロックは必ずグローバルなんてことはしなくていい!! たとえば、2つのスレッドで一つのリファレンスに入った整数を1ずつ加えながら表示 するプログラムを考える。
ロックを獲得しないと...。同じ数字が2回表示されることがある。not_sequential.ml
ロックを用意して2スレッドが排他的にfのなかを実行するようにする sequential.ml
NDBMは文字列のキーと文字列の値を格納する簡単なデータベース。
Dbm.opendbm: string -> open_flag list -> int -> t
データベース名と、モード、データベースファイルのアクセス権限を 引数にとる。モードはデータベースの読み込み、書き込み、作成を表したもので 下のように定義されている。これをリストにして渡す。データベース記述子を返す。type open_flag = | Dbm_rdonly (* 読むだけ *) | Dbm_wronly (* 書くだけ *) | Dbm_rdwr (* 読み書き *) | Dbm_create (* 存在しなかったら作成 *)
Dbm.close : t -> unit
データベースを閉じる。
Dbm.find : string -> string
キーを指定して検索する。存在しない場合はNot_found(Pervasivesモジュールに 定義されている)を投げる。
Dbm.add : string -> string -> unit
データベースにデータを加える。第一引数にキー、第二引数にデータを指定する。 既にキーがある場合はDbm_errorを投げる。
Dbm.replace : string -> string -> unit
addとほぼ同じだが、既にキーがある場合は書き換える。
Dbm.remove : t -> string -> unit
キーを指定してデータを削除する。キーが内場合はDbm_errorを投げる。
Dbm.firstkey : t -> string
最初のキーを返す。順序は不定。
Dbm.nextkey : t -> string
次のキーを返す。順序は不定。
Dbm.iter : (string -> string -> 'a) -> t -> unit
関数をキーとデータに対して適用する。引数の関数には第一引数に キー、第二引数にデータが渡される。
サンプル
db.ml
座標のとり方は数学と同じで左から右にx軸、下から上にy軸がのびる。 左下隅が原点になる。
Graphics.open_graph string -> unit
グラフィックスウィンドウを表示する。引数は表示するディスプレイの 位置、大きさを指定する文字列。どのように解釈されるかは実装依存。
この文字列の解釈の仕方についてはマニュアルに書いてある。
" 100x100+0-0" はサイズ100x100のウィンドウを位置(0,0)に開くことを意味する。 この文字列の最初のスペースは必要(display-nameを指定せず、位置のみ指定 する場合)。X-Windowシステムでのdisplay-nameを指定できる。 (mamewo:0のような)。 空文字列を与えるとデフォルトの設定で表示する。
Graphics.set_color color -> unit
色を設定する。色を表すデータ型型colorはGraphicsモジュール内でintとし て定義されている。0xRRGGBBのようにRGBを16進2桁ずつ割り当てられている。rgbという 3引数(RGB)をとりcolorを返す関数もある。
Graphics.fill_poly (int * int) array -> unit
多角形を描き塗りつぶす。多角形の頂点の座標の配列を受け取る。
サンプル
g.ml
prototype.ml (気ままなお絵書き)
prototype1_2.ml (もっと気ままに)
drawing.ml (これが真のお絵書き)
graphParser.ml (そしてちょっとした テキスト処理)
graphParser2.ml (一行ずつの処理)
サイズに制限無し。数値のみ。多次元配列(16次まで)を簡単に扱える。
インタプリタ上で使うにはbigarray.cmaを組み込む。ocamlmktop -o mytop bigarray.cma ./mytop3.04に変更したら #load "bigarray.cma"で使えた...。
Bigarrayモジュール内にArray1,Array2,Array3というモジュールが定義されている。 これらはそれぞれ一次元、二次元、三次元配列である。Bigarrayのインスタンスは ('a,'b,'c) tのような型を持つ。'aはOcamlでの型、'bは実際にBigarrayに格納されている 型、'cは配列のレイアウト(c_layout/fortrun_layout)の型である。Ocamlでfloatは 倍精度(64bit)であるが、Bigarrayに格納するfloatは単精度(32bit)であるという ことが可能である。Ocamlの型と実際に格納されている値の型との対応を決めるのが ('a,'b) kind型である。
Array1.create [kind] [layout] [size]
生成。Bigarray.int,Bigarray.float32のようなkindとBigarray.c_layoutの ようなlayoutとサイズを与える。
Array1.dim [bigarray]
配列長
Array1.set [bigarray] [index] [element]
代入
Array1.get [bigarray] [index]
参照
let s = Unix.socket ~domain:Unix.PF_INET ~kind:Unix.SOCK_STREAM ~protocol:0 in ,..逆にUnixLabelsを使うならラベルを付けないと怒られる。
Unix.getcwd: unit -> string
作業ディレクトリ名を得る
例 cwd.ml
Unix.execv: string -> string array -> unit
指定された実行ファイルに指定した引数と現在のプロセスの環境を渡して実行する。execvp (実行ファイルをパスから検索する) execve (環境を渡せる) などの関数もある。Unix.execv のあとにかかれたコードは実行されない。
例 exec_script.ml
Unix.in_channel_of_descr: file_descr -> in_channel
Unix.out_channel_of_descr: file_descr -> out_channel
Unix.descr_of_in_channel: in_channel -> file_descr
Unix.descr_of_out_channel: out_channel -> file_descr
ファイルディスクリプタとチャネルの変換。
Unix.opendir: string -> dir_handle
ディレクトリを開く
Unix.readdir: dir_handle -> string
ディレクトリ内の次のエントリを読む。終りならばEnd_of_file例外が飛ぶ。
Unix.closedir: dir_handle -> unit
ディレクトリを閉じる
Unix.gethostbyname: string -> Unix.host_entry
ホスト名からホスト情報を得る。host_entryのh_addr_listがIPアドレスを表すinet_addrの 配列。これは抽象型。inet_addrの文字列の変換はstring_of_inet_addr関数を使う。
Unix.socket: socket_domain -> socket_type -> int -> file_descr
ソケットを生成する。socket_domainは Unixドメイン(PF_UNIX)とInternetドメイン (PF_INET)がある。socket_typeは通信の階層に応じて、SOCK_STREAM,SOCK_DGRAM,SOCK_RAW,SOCK_SEQPACKET がある。3つめの引数は~protocolというラベルが付けられている。0にするとデフォルトのプロトコルが 使用される。file_descrが変えるので、Unix.read,Unix.write (send*,recv*)を使って読み書きする。
Unix.bind: file_descr -> sockaddr -> unit
ソケットに名前を付ける。指定したアドレスをソケットに対応づける。sockaddrは ADDR_UNIX かADDR_INET。SOCKETのドメインに応じて決める。ADDR_UNIXはファイル名を引数にとる。ADDR_INETは inet_addrとポート番号(int)のtupleを取る。
Unix.connect : file_descr -> addr:sockaddr -> unit
接続する。sockaddrは ADDR_UNIX , ADDR_INET がある。前者はマシン内での 通信に使用し、引数にファイル名を指定する。後者は異なるマシン間での通信に 使用し、IP アドレスと、ポート番号を指定する。IP アドレスは 数字を . で区切った IP アドレスを表す文字列があれば、Unix.inet_addr_of_string 関数で得られる。 マシンの名前がわかっている場合は gethostbyname で名前を問い合わせて、ホスト情報 を得て (host_entry 型) そこの h_addr_list フィールドをみる。これは IP アドレスの 配列になっている。
例 http.ml, url.ml, proxy.ml, ftp.ml
Unix.listen: file_descr -> int -> unit
ソケットに対して受け付ける接続の最大数を設定。
Unix.fork: unit -> int = <fun>
プロセス生成。返り値が0ならば子プロセス。 fork.ml
Unix.system string -> Unix.process_status
sh(シェル)を使ってコマンド実行する。
Unix.pipe: unit -> Unix.file_descr * Unix.file_descr
パイプ生成。ペアの一番目の要素が読み込み口、二番目が書き込み口
例 pipe.ml / pipe_session.txt
Unix.open_process_out: string -> Pervasives.out_channel
Unix.open_process_in: string -> Pervasives.in_channel
引数で指定された文字列をシェル (sh) で解釈実行する。そのシェルの標準入力、標準出力につながっているチャネルを返す。
例 external_process.ml
Unix.mktime: : Unix.tm -> float * Unix.tm
Unix.tmの 年月日、時分、夏時間か?を埋めて他のフィールドである、曜日、 一年のうちで何日目かを埋めたUnix.tmを返してもらう関数。Cにもmktimeという同様な 関数がある。曜日は日曜日が0に対応する。月は0 originであり、これはCのmktimeと 同じである。年は1900年との差である。
例# let a = { Unix.tm_sec = 0; Unix.tm_min = 0; Unix.tm_hour = 0; Unix.tm_mday = 13; Unix.tm_mon = 8; Unix.tm_year = 102; Unix.tm_wday = 0; Unix.tm_yday = 0; Unix.tm_isdst = false };; val a : Unix.tm = {Unix.tm_sec = 0; Unix.tm_min = 0; Unix.tm_hour = 0; Unix.tm_mday = 13; Unix.tm_mon = 8; Unix.tm_year = 102; Unix.tm_wday = 0; Unix.tm_yday = 0; Unix.tm_isdst = false} # Unix.mktime a;; - : float * Unix.tm = (1031842800., {Unix.tm_sec = 0; Unix.tm_min = 0; Unix.tm_hour = 0; Unix.tm_mday = 13; Unix.tm_mon = 8; Unix.tm_year = 102; Unix.tm_wday = 5; Unix.tm_yday = 255; Unix.tm_isdst = false})2002/ 9/13は金曜日。2002/ 1/ 1から数えると255日目である。
difftime.ml
localtime.ml
current_date_string.ml
サンプル
readdir.ml
listen.ml
listen2.ml
easy_server.ml
fork.ml
pipe.ml
read.ml 端末操作。エコーを止めるとか
ipv6_addr.ml ocaml 3.08.0 から IPv6 に対応した。ちょっとテスト
ipv6_wget.ml ipv6でローカルに たっているWebサーバーからGET!
create でWidgetを生成して (create では初期値を設定できることが多い ) configure_get, configure で状態を取得 / 設定する。 これらは Widget 毎にだいたい定義されている。
Tk.pack で親 window に配置する。 Tk.mainLoop を呼び出すと実行が始まる。
Winfo モジュールに Widget の情報を取り出す関数が定義されている。 Widget の親 Winfo.parent など。Clipboard
Labltk 内部のローカルなクリップボードを操作する。
例
clipboard_test.mlSelection
今度は X レベルに及ぶ copy & paste
例
ラベルが selection を得るとどうなるのだろう? selection_test.ml
テキストエントリとかテキストボックスも同様!? entry_selection.mlListbox
例
insert で要素を挿入する。挿入にはいろいろあるようで。。 listbox_test.mlScrollbar
javaのSwing だと ScrollPane というパネルにスクロールバーでスクロールする 物を「入れる」記述で簡単に書けるようになっている。Labltkでは command ラベルが ついた引数で関連づけているようである。
例
otherlibs/labltk/browser/ の中のソースを参考にした。 scrollbar_test.mlBalloon
触ってしばらくするとひょこっとでてくるあれ。黄色しかないのだろうか? (涙)
例
whatsballoon.mlFrame
配置のための Widget のようだ。 GTKでいう hbox, vbox のような箱。
listbox_with_filter.mlRadiobutton
GUIのAPIのセンスはここで見えてくると僕は思っている。labltkはなかなかナイス。 同じ変数 (Textvariable.textVariable) に関係付ける。確か GTK ではラジオボタンのグループ に突っ込んでいく。まぁグループを変数と言い替えただけですが。。。。
でも、一般的にRadioボタンって使いますが、 なんでradioボタンと呼ばれるのかは知らないですねぇ。なんでだろ〜。
例
radio.mlTimer
コールバックをさくさくっと登録できていいなぁ。
例
labltk_timer_test.ml
multiple_timer.mlCanvas/Imagephoto
ただただサンプルの tetris.ml を参考にして張り付けてみました。ってだけ。
例
image.mlサンプルアプリケーション
ラベルをはるだけ。最も簡単なテストプログラム labeltest.ml
これも多分簡単なの labltktest.ml
Frameを用いてlayout layout.ml
Canvasのサンプル can.ml
TextEntryとボタン。あとクリック時の動作 (7に反応) entry_and_event.ml
Double ButtonPress <: ButtonPress ... move_dragged_oval.ml
マウスの移動は `Motion で捕捉できる。 whatsmotion.ml
ちょっとかいてみた graph_drawer.ml
パスワード入力ダイアログ get_password.ml
もう一つ window を開いてみる例。そのwindowがcloseされるまで親windowが待つ (Tkwait.window) easy_biff.ml
おまけ。 pop.ml mytcp.ml
パスワードを入れるチャンスは1回!! (間違えたら再び立ち上げよう)
メールの数が前回から変化したら色を変える。クリックで戻る
geometryはXの形式の文字列で指定する。where_am_i.ml
日本語のテスト。ただそれだけ。 japanese.ml
しょわしない(標準語?)ticker ticker.ml
labltkサンプルプログラム集。
アンテナ mbiff がいろいろ使っている。 Entry、Balloon、Label。
以前書いたような気がするけど。。。。キーの名前を出力 keytest.mlメモ
ocaml-3.06/otherlibs/labltk/examples_labltk/ にサンプルプログラムがある。
整数リテラル
普通の数字は10進数
頭に 0xか0X を付けると16進数
0o,0O で8進数
0b,0B で2進数が書ける
if文はelseを省略することもできる。その際if文全体の型はunitになる。
(あたりまえ)
文字列は開始位置、長さを指定して扱う。
コードサイズがおおきいと、Stack Overflowでコンパイルできない。
モジュールについて知りたければocamlbrowserを使う。
ocamlbrowserのオプション-Iでパスを指定することで新たなモジュール のAPIをブラウズできる。
おまけ
ocaml 3.07 patch 2 で ocamlbrowser のネイティブバージョンをつくるための Makefile のパッチ。ocamlbrowser.opt-3.07-2.patch
patch -p0 < ocamlbrowser.opt-3.07-2.patch
して ./configure && make world && make opt
すると、otherlibs/labltk/browser/ocamlbrowser.opt ができる
コンパイル単位
一つのファイルはファイル名のprefix一文字目を大文字にしたstructureとして 扱われる。set.ml等とつけるとライブラリのSet moduleと重なって良くない。 ライブラリのUnixLabelsはunixLabels.* のように命名されている。コンパイラ
ocamlには、ocamlrun上で動くバイトコードを生成するocamlcと、プラットホーム によってはネイティヴコードをはくocamloptがある。分割コンパイルもサポートしている。 ocamlc,ocamloptはどちらもocamlrunというバイトコードインタプリタ上で動作しているが ネイティブ上で動作するコンパイラを生成することもできる。(make opt.opt) ocamlc.opt,ocamlopt.optという名前のプログラムがそれである。
リンクは依存される側を先に書かなければならない。例えばUnix moduleを使用している quick.mlというプログラムがあるとすると、
ocamlcopt.opt /usr/local/lib/ocaml/unix.cmxa quick.ml -o quick
という風にコンパイルする。(ネイティブの場合) ちなみにバイトコードの場合は
ocamlc.opt /usr/local/lib/ocaml/unix.cma quick.ml -o quickオプション
-c コンパイルのみ。オブジェクトコード生成 -o 出力ファイル名の指定 -I [dir] .cmiファイルのあるディレクトリを指定 -i 定義された関数名、名前を出力 拡張子
.c,.o,.a,.so等も使えるらしい。
.mli インターフェイス(input) .ml 実装(input) .cmi コンパイルされたインターフェイス .cmo コンパイルされた実装(オブジェクトバイトコード) .cmx コンパイルされた実装(ネイティブオブジェクトコード) .cmxa ライブラリ OCamlMakefile
OcamlのためのMakefileの雛型。これを使うとMakefileが簡単に書ける。
例) quick.mlのコンパイル。内部ではUnixモジュールを使用している。ネイティブ コードを生成する。OCAMLMAKEFILE = /home/tak/lib/ocaml/OcamlMakefile SOURCES = quick.ml RESULT = quick LIBS = unix all: native-code include $(OCAMLMAKEFILE)SOURCE,RESULT
ソースファイルと結果ファイルの名前。デフォルトでそれぞれ foo.ml,fooになる。
LIBS
ライブラリの名前。拡張子はいらない。
all: (コンパイル結果の指定)
native-code,byte-codeはもちろん、debug-codeも簡単にコンパイルできる。makeの引数 にbc(バイトコード)、nc(ネイティブコード)、dc(デバッグコード -gオプションを付けた コンパイル)を与えることで、コンパイル結果を変えることができる。
include
OcamlMakefileを最後にincludeしておく。
使用するコンパイラ
使用するコンパイラはデフォルトでバイトコードバージョン(ocamlc,ocamlopt)が 使用される。変数 OCAMLC,OCAMLOPTを変更することで使用するコンパイラを変更 できる。(ocamlc.opt,ocamlopt.optなど)
複数のターゲットがある場合export OCAMLMAKEFILE = ../OcamlMakefile EX1 = SOURCES=ex1.ml RESULT=ex1 THREADS=yes EX2 = SOURCES=ex2.ml RESULT=ex2 THREADS=yes all: ex1 ex2 ex1: $(MAKE) -f $(OCAMLMAKEFILE) $(EX1) ex2: $(MAKE) -f $(OCAMLMAKEFILE) $(EX2)引数を定義して、makeに渡す。OcamlMakefileをmakeの引数として渡す。
プライベートで使うライブラリの構築例
Makefile
mylib.ml , mylib.mli
コンパイル
> make ncl
ライブラリの使い方
> ocamlopt.opt -I /home/tak/lib/ocaml mylib.cmx useLibraryTest.ml -o use
/home/tak/lib/ocaml はライブラリへのパス。 findlibを使えば簡単になるのか?わからないけど。メモ
"Files /usr/local/lib/ocaml/unix.cmxa and /usr/local/lib/ocaml/unix.cmxa both define a module named Unix" というエラーメッセージがでる
THREAD変数を定義しているときはunixとthreadsライブラリがリンクされるので、LIBS変数には含めないようにする。
バイトコードコンパイラ
オプション
-custom ocamlrun無しで走るコードを生成
-dlambda, -drawlambda など dからはじまるオプションのほとんどは ダンプオプション。Ocamlで使われる中間言語をダンプする。utils/clflags.ml にオプションによってセット、クリアされるフラグや変数がが定義されている。
実行順序について考えてみる
ファイル fst.ml , snd.ml
ケース1
> ocamlc -c fst.ml
> ocamlc -c snd.ml
> ocamlc -o app fst.cmo snd.cmo
> ./app
fst initialized
snd initialized
ケース2
> ocamlc -o app snd.cmo fst.cmo
> ./app
snd initialized
fst initialized
リンク順は大事
指定したオブジェクトファイルが起動時に読み込まれたトップレベル を作成する。
オプション
-custom Cのオブジェクトファイルのリンクを可能にする
対話的に関数を呼んだり型を確認できる。
例ocamlc -a -o modML.cma modules.cmo miniML.cmo miniMLparser.cmo miniMLlexer.cmo miniMLmain.cmo
# バイトコードオブジェクトファイルをまとめる (個々をloadするのが面倒なので) > ocamlc -a -o modML.cma modules.cmo miniML.cmo miniMLparser.cmo miniMLlexer.cmo miniMLmain.cmo > ocaml Objective Caml version 3.04 # #load "modML.cma";; # MiniMLmain.enter_val ;; - : string -> MiniML.MLEnv.Mod.Core.val_type -> unit = <fun>
ocamlのデバッガ。
使い方
コマンドプロンプトから
> ocamldebug [options] [program] [arguments]
オプションコマンド
-I [dir] include directoryに [dir]を加える -s [filename] ソケットの名前を付ける -c [count] チェックポイントの最大値を決定する。 -cd [dir] カレントディレクトリを変更する -emacs Emacs上でデバッガを走らせる
help デバッガのコマンドについてのヘルプを表示 show デバッガの情報表示。コマンドライン引数、デバッグ中のプログラム名など goto 与えられたTimeに飛ぶ backstep 前のイベントに達するまでプログラムを巻きもどす。引数Nを あたえると、これをN回繰り返す
gcovのようにソースにコール回数をコメントとしていれたものを得るには ocamlcpでコンパイルし(バイトコード)、コンパイルされたコードを実行し、ocamlprof で結果を見る。実行時間に関する情報はGNUのツールgprofを使う。-pオプションをつけ てネイティブコードコンパイルし、実行、gprofで結果を見る。
例 libSequence.mlでの実行例> make pbc ## OcamlMakefileでは pbc=prifiling byte code pnc=profiling native code > ./prime 100 > ocamlprof libSequence.ml > ocamlprof_result.txt> make pnc > ./prime 100 > gprof prime > gprof_result.txt.gz
ocamlのバイトコードを読みたいときは、ocamlc の -dinstr オプションを使用するか、 ocaml の tools ディレクトリにある dumpobj を使うと読める。
オブジェクトファイルからそのオブジェクトファイルの情報を得る objinfo も tools ディレクトリにある。
dumpobj, objinfo ともにデフォルトでは生成されないようである。 tools ディレクトリで make dumpobj ; make objinfo すれば得られる
参考
Re: [Caml-list] Is there a "disassembler" for Caml?
byterunにあるCのコードを参考にして書くとよい。 引数は全てvalue型。具体的にはCのlong型になっている。CAMLprimはコンパイラに 必要な指示をあたえる。Windowsに関係あるようで。
Ocaml側からはexternal宣言でCの関数にOcamlの名前と型を付ける。
サンプル(とりあえず呼び出せることだけ確認)
prim.c
p.ml
コンパイルは
> gcc -I/usr/local/lib/ocaml -c prim.c
> ocamlc -c p.ml
> ocamlc -custom prim.o p.cmo -o p
または
> gcc -I/usr/local/lib/ocaml -c prim.c
> ocamlopt -c p.ml
> ocamlopt prim.o p.cmx -o P
caml_and_c.tar.gzCamlIDLを使用する
CamlIDL は Ocaml から C の 関数を呼ぶためのスタブコードを生成するプログラムである。 Ocaml と C の 関数の間でやりとりされるデータの変換を行う。使用例
parsedate-2003-08-06.tar.gz
The InterNetNews library の parsedate を呼ぶスタブを書く。スタブ自体は 単純である。 sys/types.h をインクルードしなければいけないので、それを quote で入れておく。
libinn.a のようなライブラリとのリンクを簡単に行うには ocamlmklib を 用いて ocaml のライブラリを作っておくと楽である。 ocamlmklib は .o , .cmo , .a ファイルを引数にとって、それを一つのライブラリにまとめる。
Makefile は clean しか定義してないです (汗)
コンパイルするには build.sh スクリプトを使ってください。
おまけ。 CamlIDL CamlIDL を使いながら書いたメモ
ocaml自身バイトコードでありocamlrun上で走る。ocamlが単独で走る ようにするために、ocamlmktopを次のように実行する。ocamlmktop -custom -o mocamlこのmocamlにソースを流せばよい。参考 Pratical hints for using Ocaml (mostly Unix-specific)#! ./mocaml print_string "mamewo\n";; exit 0;;
コンパイルするにはgtkInit.cm{o,x}とlablgtk.cm{a,xa}とリンクする。 -w sは複文中の文がunitでない値を返すときにでる警告を出さないようにする。
例) example/内のprogressbar.mlのネイティブコードコンパイル
> ocamlopt -I /usr/local/lib/ocaml/lablgtk -w s -c progressbar.ml
> ocamlopt -I /usr/local/lib/ocaml/lablgtk -w s lablgtk.cmxa gtkInit.cmx progressbar.cmx -o progress
> ./progress
GWindow,GButtonなどG*がWidgetに対応する。それぞれはクラスで定義されている。 GMain.main () がgtk_main()に対応している。
小さいサンプル(gtktest.ml)
lablgtk2のサンプル(gtk2_hello.ml)
TreeViewを使うがListStoreでリストを表示するサンプル (gtk2_treeview_list.ml)
string listを表示するように関数化(show_string_list.ml)
ラベルつき木を定義し、それを表示するように関数化(show_string_tree.ml)
TreeViewで2列表示してみる (two_column_tree.ml)
xml-lightを使ってXML(slashdot.rdf)のパーズ結果を表示(show_xml_tree.ml)
show_xml_tree.ml のTreeViewをScrolledWindowに入れるようにしてスクロールを可能にしたもの (gtk2_scrollwindow.ml)
Pango markupを使って装飾 (gtk2_treeview_with_tag.ml)![]()
HTMLを表示してみる(show_html_tree.tar.gz)
GtkSignal.connect_by_name を利用してみる (signal_connect.ml)
GtkWidget.S など S という名前のmoduleにGtkSignalの引数 sgn に与えるsignalを表す 値が定義されている。 (例 GtkWidget.S.key_press)
key-press-eventをとらえる。GtkSignal.connectを使ってみる (gtk2_keypressed.ml)
字句解析器(lexer)、構文解析器(parser)を生成する。
メモ
ocamlyaccからパーザープログラムのソースとインターフェイス(ml,mli)ファイルが 生成される。mlファイルをコンパイルする前にmliファイルをコンパイルする。
lexbufをLexing.from_*から生成。
ocamllexにはネイティブ版ocamllex.optがある。
ocamlyaccのオプション
-v 構文解析の表を出力する(拡張子は.output) -b[prefix] 出力するプログラムのprefixを指定
型を等価にするか隠蔽するかは signature の適用の仕方による ":" か ":>" か?
+,-はreal,intについてoverloadされている。 real同士かint同士。型を付けずに関数定義すると intに型付けされる。- val f = fn x => fn y => x + y;; val f = fn : int -> int -> int - val f = fn x:real => fn y:real => x + y;; val f = fn : real -> real -> real
Ocamlのエラージャンプ
OcamlのAPIサーチ(リージョンで指定、完全一致)
search_ocaml_type.el, search_type.ml, type_server.ml, type_server_with_type_annotation.ml
まとめてみた。ちょっと改良 searchtype-2004-01-08.tar.gz
コマンドは configure; make world; make opt; make opt.opt; make install; make installopt。emacsディレクトリにEmacs lispのためのMakefileがある。 EMACSDIRを指定して、 make install; make ocamltags; make install-ocamltags。
run-camlをEmacsで実行するとinf-caml.elにエラーがあるらしく、うまくいかない。 (inf-caml.elの367行目 (lookup-key caml-mode-map [menu-bar caml])がnilを返す) のでこのlet文をコメントアウトしたらrun-camlがうまく起動した。info で書かれたマニュアルのインストール
info ってどういう仕組みでジャンプしているんだろう...?
tar xfvz ocaml-3.07-refman.info.tar.gz ; cd infoman ; cp /usr/share/info
/usr/share/info/dir の適当なところに以下の行を追加する。この括弧の中の文字列を元にしてジャンプ先を決めているのだろうか? なぞ。 ん、Topノードに戻れないよぉ (涙)
* Ocaml 3.07: (ocaml). Ocaml Language Reference Manual
比較演算子 (>),(<),(>=),(<=),(=)はオーバーロードされている。
ライブラリはstdlibにソースがある。Cで定義された関数はbyterunにあったりする。# let x = 1.2 in let y = 1.2 in x == y;; - : bool = false # let x = 1.2 in let y = x in x == y;; - : bool = true # let x = 1 in let y = 1 in x == y;; - : bool = truelet recでデータ定義することで循環するデータ構造を簡単に定義できる。# type mrec = { name:string ; mutable ptr:mrec };; (* 再帰的なデータ構造 *) type mrec = { name : string; mutable ptr : mrec; } # let rec me = { name = "takashi"; ptr = me };; (* 自分を入れる *) val me : mrec = {name = "takashi"; ptr = {name = "takashi"; ptr = {name = "takashi"; ptr = ... # type graph = Graph of string * graph;; type graph = Graph of string * graph # let rec a = Graph("tak",a);; val a : graph = Graph ("tak", Graph ("tak", ... # let rec a = Graph("tak",b) and b = Graph("mamewo",a);; val a : graph = Graph ("tak", Graph ("mamewo", ... val b : graph = Graph ("mamewo", Graph ("tak", ...graph_session.txt (いろいろ書いてみる)
let-bindingはpattern [: typexpr] = expr 。代入の左辺はパターン なので例えばこんなことができる。# let a,b = 1,2;; val a : int = 1 val b : int = 2
ocamlfindcmxaはaとともにインストール
remove [packagename] ライブラリの削除 install [packagename] [filelist] ライブラリの追加
getopt
by Alain Frisch
まず、findlibをインストールしなければならない。
parse_cmdline Getopt.opt list -> (string -> unit) -> unit
Getopt.optはタプル。短いコマンド、長いコマンド、引数無しのハンドラ、引数つきのハンドラ をタプルにする。ハンドラはオプション。このオプションの使い方で引数を許すかどうかを決める。
オプションは短いオプションと長いオプションの2種類ある。
短いオプション
-o file
-ofile
一つの'-'に続いてオプションの文字を入れる。引数は直後にあたえても、スペースを はさんで与えてもよい。
長いオプション
--option=value
二つの連続した'-'に続きオプション名を指定する。スペースを入れずに=で区切り 引数を指定する。
サンプルプログラム get.ml
ocamlweb
Ocamlのソースをtexのソースに変換する。なんと最後にキーワードの 索引までついてしまうという!!すごい。コメントは地の文になるようだ。
例
> ocamlweb --ps restrictHashValueType.ml -o restrict.psocamldoc
3.05 からocamlに標準で入るようになったとか。使ってみた。(しかも日本語で 汗)
ソース drawMakefile.ml
Content-type などを加えるスクリプト add_japanese_tags.pl
結果
一部ライブラリにしてみた drawMakefile.ml , mylib.ml
-dot オプションでモジュールの依存関係を表した dot ファイルがはける。 ファイル名は ocamldoc.oot である。 これはGraphviz の入力 となるファイルである。 たとえば、
> dot -Tpng ocamldoc.out
を実行すると、png 形式の画像で依存性をみることができる。
The Caml language
Archives of Caml Weekly News
Ocamlのライブラリのリリース状況やメーリングリストで流れた質問に対する答えなど。役にたつ。 LWN.net でも読める (つながらない時 or 検索したいとき)
Developing Applications With Objective Caml
Using, Understanding, and Unraveling The OCaml Language (by Didier Remy)
Programming with Objective Caml
ocamlfind, Shell などのツール、アプリケーションを配布している。
Dimitri Ara's homepage: ocaml
ocamldsort!! モジュールを依存性をもとに topological sort する
debianのパッケージにもなっている?
The Caml Hump: Latest updates
ライブラリやツールへのリンク集
MLgraph
Ocaml を使って落書っ!!
Camlserv web-server written in ocaml
HTMLを処理できる!
(basics.ml と html.ml をコンパイルして unix.cma をリンクすれば使える。testhtml.ml)
bibtex2html: BibTeX to HTML converter
参考文献データベースファイル(.bib)からHTMLに変換する Ocaml でかかれたプログラム
Ocaml Curl Library
いろんな通信ができる HTTP, FTP, SSL..
Ocaml プログラミング入門
丁寧でわかりやすいです。
OCamlチュートリアル
OCaml.JP
ocamlkf (ocamlでかかれた日本語文字コード変換プログラム) にはしびれました。 (サンプルコード ocamlkf (ocamlでかかれた日本語文字コード変換プログラム) にはしびれました。 (サンプルコード ocamljcode.ml)
数理科学的バグ撲滅方法論のすすめ:ITpro
Ocamlでscript
モジュール
functorの例(abstract/manifest型を中心にした例)
Description of Standard ML
SMLの文法。リンクが多くて読みやすい
Ocamlのソースコードを眺める
Ocaml Internal
ocaml 3.06 の内部をみてみた
Programs (このサイトのプログラム一覧)
OcamlでXML処理
Caml Weekly Newsをもとにしたメモです。実際に自分で使ってみてないものも載せることにしてみました。サイズ可変の配列がほしい
Ocaml ExtLibウェブアプリケーションを書きたい
WDialog HomepageMakefile を書くのが面倒だ
OCamake例外がどこから投げられたかを表示させたい
Stop at exception
ocamlrun -b で実行
Line number for index out of bounds
環境変数 OCAMLRUNPARAMをつかってocamlrunにオプションを渡す
サンプルプログラム exception_trace.mlライブラリを簡単にインストールしたい
GODI: The source-code Objective Caml distributionocamlのstatic call-graphを描くには?
Generating a call-graph
関数の引数に関数をわたすことができるので、引数にどの 関数が渡されうるかを調べるために Control-flow のみならず Data-flow の解析も必要。
0-CFA, K-CFA (Shivers, O., Control-flow analysis in Scheme), polymorphic splitting って何だろう?
Principles of Program Analysis ←ほしいなOcamlコンパイラの実装を知りたい
Inner workings of Caml compilerC のパーザーのプロトタイプ
A 3D animation of Linux source code development
linux kernel のファイルの間の依存性を 3D で描画してビデオで見せるっていう プログラムがあって、そこでパーザーを書くのに ocaml が使われた。
このパーザーをちょっと使ってみるテスト c_parser_driver-2003-12-27.tar.gz
いつものようにVCGと併せて遊ぶ c_parser_driver-2004-01-01.tar.gzOcamlの値の可視化
Jean-Christophe Fillietre : Programming の displaySMLからOcamlへのお手軽変換
SML -> Ocaml
caml4pを利用したおてがる変換なので変換後のコードは正しいとは限らないらしいOcamlでかかれたWebサーバー
Ocsigen
pcre pcre-ocaml ocaml-ssl ocamlnet などを入れねばならずインストールはちょっと面倒
# Printf.printf ;; - : ('a, out_channel, unit) format -> 'a = <fun> # Printf.printf "%d";; - : int -> unit = <fun>これを実現する心は? (前の引数の値そのものによって出力の型が変化する)
formatと値を動的に変化させる (only_printf.ml)
このプログラムは型エラーを生じる。 第一引数は format型であり、string型 ではないのだ。じゃぁ、format型ってなんだろう?# Printf.scan_format;; - : string -> int -> (string -> int -> 'a) -> ('b -> 'c -> int -> 'a) -> ('d -> int -> 'a) -> 'a = <fun>が怪しげ。っていっても関数名にformatって付いているだけで、型にはformatなんて 一言も書いてない。もう少し調べていくと、もっと怪しげなformatモジュールがある。 でも、format型のものを返す関数がないようなきがする......。formatって何?# ("%s": (string -> 'a, out_channel, unit) format);; - : (string -> unit, out_channel, unit) format = <abstr>んんんんん?# ("%d": (string -> 'a, out_channel, unit) format);; Characters 1-5: ("%d": (string -> 'a, out_channel, unit) format);; ^^^^ This expression has type (int -> 'a, 'b, 'a) format but is here used with type (string -> 'c, out_channel, unit) format # ("%d": (int -> 'a, out_channel, unit) format);; - : (int -> unit, out_channel, unit) format = <abstr>型システムに組み込まれているのかな? (format文字列から型を推論)
うーん、こういうものは切り離して考えてみたい気がする。
もちろん、このリテラルはデフォルトで string 型# "%s";; - : string = "%s"
Marshal と同じノリでいってみようか。とおもっても駄目らしい。
型におもいをはせる# let head::tail = (match Str.split (Str.regexp ":+") str with [] -> raise Not_found | x -> x);; Characters 4-14: Warning: this pattern-matching is not exhaustive. Here is an example of a value that is not matched: [] let head::tail = (match Str.split (Str.regexp ":+") str with [] -> raise Not_found | x -> x);; ^^^^^^^^^^Strモジュールの「暗に大域的な状態(マッチした位置など)をもつこと」におもいをはせてみる
threadTest.ml 他のThreadのマッチ結果が見える。(泣)
rightThreadTest.ml ロックを使ってみた
processTest.ml Strモジュールの「副作用」の部分もforkするから大丈夫。
openとuse
openはパスを省略するために使用。includeはモジュールの内容を そのまま展開。
一部だけ変更したrecordを返す式# type point = { x: int ; y: int };; type point = { x : int; y : int; } # let p1 = { x = 1; y = 2 };; val p1 : point = {x = 1; y = 2} # let p2 = { p1 with x = 1000 };; val p2 : point = {x = 1000; y = 2} # match p2 with { x = xx } -> xx;; - : int = 1000ついでにrecordのマッチ。(しかも一部)レコードのフィールド名
{ Unix.tm_sec = 0; Unix.tm_min = 0; Unix.tm_hour = 0; Unix.tm_mday = 1; Unix.tm_mon = 1; Unix.tm_year = 70; Unix.tm_wday = 0; Unix.tm_yday = 0; Unix.tm_isdst = false };; - : Unix.tm = {Unix.tm_sec = 0; Unix.tm_min = 0; Unix.tm_hour = 0; Unix.tm_mday = 1; Unix.tm_mon = 1; Unix.tm_year = 70; Unix.tm_wday = 0; Unix.tm_yday = 0; Unix.tm_isdst = false}型はsignatureで制限するからいいやと思ってみる
cast.ml
名前のついたsignatureじゃなくていいじゃんと思ってみる
reveal.ml
exitの返り値は多相型# if true then "tak" else exit 1 ;; - : string = "tak" # exit;; - : int -> 'a = <fun>いつでもexitはできる。
aliasってぇ
型に別名を付けるとは!?type t = a as 'moge - : Parsetree.signature = [{Parsetree.psig_desc = Parsetree.Psig_type [("t", {Parsetree.ptype_params = []; Parsetree.ptype_cstrs = []; Parsetree.ptype_kind = Parsetree.Ptype_abstract; Parsetree.ptype_manifest = Some {Parsetree.ptyp_desc = Parsetree.Ptyp_alias ({Parsetree.ptyp_desc = Parsetree.Ptyp_constr (Longident.Lident "a", []); Parsetree.ptyp_loc = {Location.loc_start = 59; Location.loc_end = 60; Location.loc_ghost = false}}, "moge"); Parsetree.ptyp_loc = {Location.loc_start = 59; Location.loc_end = 69; Location.loc_ghost = false}}; Parsetree.ptype_variance = []; Parsetree.ptype_loc = {Location.loc_start = 54; Location.loc_end = 69; Location.loc_ghost = false}})]; Parsetree.psig_loc = {Location.loc_start = 50; Location.loc_end = 69; Location.loc_ghost = false}}]
インタプリタocamlにバイトコードライブラリを読み込ませて遊ぶ
バイトコードライブラリに入っている関数の型を知りたいなら、ちゃんと対応する cmiファイルがあるパスを -I オプションで教えてあげないといけない。というよりも Unbound とかいわれるので、使えるようにするにはちゃんと教えなきゃならん。例
## 作成 > ocamlc -I utils -I utils -I parsing `tsort_cmo .depend -g typing/typemod.ml -setE .cmo -e` -a -o typemod.cma > ocaml Objective Caml version 3.06 # #load "typemod.cma";; # Typemod.type_module;; Characters 0-19: Typemod.type_module;; ^^^^^^^^^^^^^^^^^^^ Unbound value Typemod.type_module ## ↑そう、cmiファイルがないと分かってくれないのであった ## (cmi ファイルはtyping ディレクトリ内にある) > ocaml -I typing Objective Caml version 3.06 # #load "typemod.cma";; # Typemod.type_module;; - : Env.t -> Parsetree.module_expr -> Typedtree.module_expr = <fun>
あれ、そうなの# let (f, g) = (fun x -> x, 1);; Characters 14-27: let (f, g) = (fun x -> x, 1);; ^^^^^^^^^^^^^ This expression should not be a function, the expected type is 'a * 'bちがうぅ。,の結合力が -> より強いのであった# let (f, g) = ((fun x -> x), 1) ;; val f : 'a -> 'a = <fun> val g : int = 1
疑問
Map.Make の結果の signature 内での型の宣言# type key = String.t and + 'a t;; type key = String.t type +'a t+ ってなんだろう?
マニュアルによると、型変数の前には + か - をつけることができて、それぞれ covariant , contravariant な変数であることを表している。もうちょっと型を勉強しよう (汗) manual016.html
あとで考えたいこと
whynot_crawler.ml の型エラー
Caml-listより
# let ring l = let rec r = l @ r in r;; Characters 25-30: let ring l = let rec r = l @ r in r;; ^^^^^ This kind of expression is not allowed as right-hand side of `let rec'
あぁ、時間の無駄
ソースコードのファイル名は小文字で始めること。別のファイルで定義されたモジュールの名前を探すとき モジュールの名前の先頭を小文字にかえた文字列 にサフィックス .cmi をつけた名前のファイルを探す。 (マニュアルの 8.3)
ocamlyacc で action の かっこの閉じ忘れは良く分からないエラーメッセージを生む。 後ろの行にエラーがあるかのように報告される。
例外処理
finally がある
# try raise Not_found with finally -> print_endline "hello";; hello - : unit = () # try () with finally -> print_endline "hello";; - : unit = ()Value restriction
友人の説明をメモ。
そもそもリファレンスと多相型は相性が悪い。例えばlet x = ref None;;
と書いたときに x の型を普通の多相型 'a option ref にしてしまって良いかというと そうではない。x := Some "mamewo" (* x : string option ref と思って代入 *) x := Some 1 (* x : int option ref と思って代入 *)
のように各代入時に型が具体化 (instantiate) されてしまったら、 x に代入 される値の型が静的に決まらないから。そこで、xには一つの型でしか使えない型 を与える (この場合'_a option ref 型を与えて、'_a はプログラム中一つの 型しか与えない) 。ここまではすぐに分かる。
さらにlet f = List.map (fun x -> x) ;;
としちゃうと f には '_a list -> '_a list 型がつく。型多相じゃないの!? このプログラムはこんな↓プログラムがあるがために多相型になれないという被害に あっている。(* let の例 *) let g = let x = ref None in fun y -> let old = !x in x := Some y; old;; (* 関数適用の例 *) let h y = (fun x -> g x) y;;この g は内部状態として リファレンスに触ってしまうので、'_a -> '_a option 型がつく。このような問題が起きるのは let で束縛する式が let や 関数適用のときに 起こりうる のでそのような場合には、型多相な部分をとりあえず単相型を与える という制限 (value restriction) を与えている。 (つまり制限が強くて、多相型 で使えるものをも制限してしまう) 束縛するものが定数、fun でつくった関数定数 だと多相型として扱えるので List.map の例ではlet f y = List.map (fun x -> x) yと書けば良い (η展開というらしい) 参考 ML演習 第 3 回
SML/NJ
signatureの適用の仕方でopaqueかmanifestか決まる。 つまり ":>" を使うか? ":" を使うか? opaque_manifest.sml
使い分けをする(というかmanifestなsignature適用の)意義(自分勝手な解釈)
- 始めから抽象型にしてしまうと、インタプリタで読み込んだ時にデータの 中身がみえなくて困るから。デバッグ時はmanifestな制限を書けて中身は 見ながらデバッグしたい場合に使う(OcamlでModule言語を学んだ時にdebugの妨げに なるのでsignatureはうっとおしいという印象をもっていた)
- functorの引数として渡すためだけに作るstructureの型(signature)が functorの引数の型のsubtypeとなっているかを定義時にチェックしたい場合に使う。
Moscow ML
help という関数に感動した。関数を名前で検索できる。moduleに期待。 ソースとドキュメントを含むtar.gzファイルを展開して example/modules/sieve.sml をみてみると、 first order module を見ることができる。Eratosthenesの篩を用いた素数表の例である。感動!! まだ 再帰的な structure の定義が可能。これらは Moscow ML の拡張。
SMLはキーワードが多くて書きにくい感じがする。structure に絡んでくるキーワードは とってもおおい。それにくらべ、関数定義も変数定義もletでできて、 module 内の みえ方を適用する signature の中見にまかせた (適用の仕方ではなくて) ocamlは すっきりしている。表現力の差はまだよくわかってないです。OcamlのソースをNamazuに食べさせる
mknmz --allow=".*.mli?" ~/download/ocaml-3.07/otherlibs/labltk ~/project/gui /usr/local/lib/ocaml/labltk/ocamldebug
Emacs上でocamldebug を走らせられる camldebug.el という Emacs Lisp がある。自動的に エラーが出たところのファイルを開いてくれて便利。
もちろん、無保証
- バグありレイトレ(球)
- ちょっとはまし 本体(proto.ml) / 数字のLexer(num_lexer.mll) / Makefile
- ガウスの消去法で連立方程式を解く。solve.ml
- かけ算表 mult_table.ml (imperative featuresを使った)
- なぞのプログラム scale_point.ml
- 状態をもつ関数 random.ml
- 式っていいよね random_round.ml
- Makefile の依存性をグラフ描画してみよう。オプションは未整備
oldDrawMakefile.ml,
Argモジュールを使ってちょっとオプションを整備した。拡張子を取り除いて 一つのノードにまとめる機能をつけた(-gオプション).depend,
結果 グラフ
コマンドライン> ocamlopt.opt str.cmx drawMakefile.ml -o drawMakefile > ./drawMakefile > result.vcg > xvcg result.vcgディレクトリ構造をサブグラフに置き換えているので、ディレクトリを折り畳む(fold) ことができる!! vcgさまさま。
もっとオプション整備したもの drawMakefile.ml- 単純な再帰 hanoi.ml
説明がたりない。(汗- 個人的なライブラリ mylib.ml と Makefile (要 OcamlMakefile)
- ocamlfindとgetoptのサンプル get.ml
- functionalではないが
graph.ml と main1.ml, main2.ml 拡張アイデア
ちょっとは実用的な実行例 使用方法
tsort_cmo.ml オプションを整備。
tsort コマンドをつかうともっと簡単に実現できるが、アルゴリズムを復習したかったので あった。
c.f. ocamldoc & Graphviz- 簡単な vcg ファイルのリーダー ocaml-vcg.tar.gz
ocamlyacc, ocamllexのサンプル。
デバッグするには lexbufを変数にバインドしておいて、このバッファの内部 状態を見ればよい- とっても中途半端に書いたプログラム get_links.ml
- 謎ってことにして treat_type.ml
- パターンマッチ match.ml
- パターンマッチ2 match2.ml
- trie を書いてみた。ただのラベル付き木 trie.ml
- trie をちょっとつかってみる。ちょっとおもったのと違う。(汗 general_trie.ml
- いや、 'a list も 'a StringMap.t も同じことですよ。とあとで気づく。型多相なデータ型 isinstance.ml
- 自分でちょこっとつかう自家製ライブラリ ocaml.tar.gz
make bcl してみよう。要 OcamlMakefile (tmpっていうディレクトリに展開されます)- これは使う前に準備が必要。ocamlの parsing/printast.ml を用いて (Ocamlの) 構文木をダンプする。 printparsetree.ml
mlファイル(実装)を渡す- Emacs Lispを観察するためのアドホック (ちょっとだけドキュメントみつつ、ほとんどEmacs Lisp ソースをみてつくった) パーザー と static な call graph (make して ./main.bc ~/.xemacs.el とか) lisp-analysis.tar.gz
lisp-analysis-2003-01-30.tar.gz
例えばこんなグラフが描けるかもね
mew で mew-summary-buffer-string に強く依存 (書き込み、読み込みする関数とそれが呼ぶ関数 mew-sumamry-buffer-string からの距離(枝の本数で定義)が2以内) する関数をグラフ化
mewを通してみたところ、なんとか通った。ただエラーがでないだけで、 でもアドホック。マクロとか、日本語とか無視するので結果は正確でない。- 頭が再帰的にまわらない瞬間 dfs.ml, typing.ml
- 意外と書いていなかったクライアントプログラム HttpClient-2003-02-08.tar.gz
- いつも通りの正規表現を用いたHTML処理 (リンクあつめ)linkCollecter-2003-02-08.tar.gz
- ネットなプログラムを中途半端にいくつか書いてみた POP, HTTP crawler-2003-07-01.tar.gz
- uncarry ってこういうことかぁ uncarry.ml
- ローカルなディレクトリと、URLとのアドホックな対応付け web_pwd.ml
- graphvizとvcgを比較してみた tools-2003-02-16.tar.gz
- だって、ほしかったんだもん。cmaのファイルの中身をちょっとみるプログラム。要 emitcode.cmi readlib.ml
2003/ 3/ 6 あるモジュールがどのライブラリに入っているか検索する機能を追加した
ん、 tools/objinfo.ml ってのと似てる。。。- やっぱ役立つ readlib.ml Balloonがどのライブラリファイルに入っているか調べるのに使った。
- labltkサンプルプログラム集。biff+アンテナ と ticker gui-2004-04-05.tar.gz / gui-2004-04-30.tar.gz
XEmacsバージョン (XEmacs 21.4.6で開発中) embiff-2004-01-05.tar.gz![]()
biff+アンテナについてのメモ Balloonを使って差出人を表示する。なぜか前回のBalloonが一瞬表示されて見苦しい。
HTTP 1.0 じゃだめなようで HTTP 1.1 のリクエストを追加した
Base64のデコード -> Mayahさんの ocamlkf を使って JIS2EUC変換をして日本語で書かれた差出人の名前を表示するようにした。
中ボタンクリックでアンテナに関連したURL (あれば) を選択 (コピー) するようにした。
OSによって性能に差があるので原因を調査中。とりあえず -exclusive オプションをつくってみた。これをつけて起動すると、socket を connect して close していない Thread が 高々一つになる。
初期の biffだけバージョン mbiff.ml, pop.ml, mbiff.ml, pop.ml, mytcp.ml
他のライブラリに依存するので autoconf マクロサンプルをいじって configure スクリプトを生成し、 configure でライブラリの存在確認をするようにした。
tickerについてのメモ
slashdot.jpなどののRSSをとってきてヘッドラインを表示する。(rdf/slash.ml, rdf/slash_with_time.ml)
新しい記事は白い文字、更新前にもあった記事は灰色で表示するようにして新鮮さを表現した。
配列アクセスに時々失敗するバグを修正した(多分) フォントを設定する -font オプションの追加。
中ボタンクリックでいま表示している記事に関連したURLを選択する (コピーする) オプション -url の追加
slashdot, asahi だけじゃなんなので CWN (Caml Weekly News) も加えてみた。
記事一覧を表示してみた (マウスの右ボタンをおす)
こんな感じ→![]()
- なるほど Base64のエンコードとデコード base64.ml
- expatを用いたXML処理 expat_test.ml
- なるほどUnicode。すごく遅いルーチン 要 JIS0208.TXT (変換表) utf.ml
そりゃ、テーブル毎回つくってりゃおそいよ。というわけで、テーブル初期化を持ち上げて 速くした utf_fast.ml
utfからEUCへの変換もかいた。どちらも変換テーブルの範疇に収まる 文字からなる文字列を想定していて完全ではない、んだろうな。- not_permitted_in_right.ml
なんで許されないのか聞いたような気がするけれど忘れた。調べてみよう
というわけで、友達の value restriction の説明を聞いて納得。詳しくは ML 演習 第 3 回- customized_parsing-2003-06-08.tar.gz (2.8M) (みつからない?)
printast.mlをつかってAbstruct Syntax Treeを出力した (treat_implementation_debug.ml)
make cleanしちゃうとちゃんとコンパイルできなくなるかも。
要 mylib.cma (自作 graph ライブラリが必要)
関数適用の関数の部分は式であることにふと気付き、修正した。 (treat_implementation.ml) がまだ完全ではない。
ちょっとした整理。build.sh で drawOcamlGraph を作成可能にした customized_parsing-2003-09-27.tar.gz- Ocamlファイルのprefixからそのprefixにマッチするソースファイル (ml, mliなど) の ファイル名を出力するプログラム getOcamlSources.pl
と、その使い方- VCGファイルから、そのファイル内で定義されているノードのタイトルまたはラベル名を出力する プログラム get_nodes.ml を追加した。graph-2003-06-09.tar.gz
VCGから部分グラフをとってくるプログラムを書いた。必要なファイルを一つの ディレクトリにまとめた (汗) vcg-2003-10-03.tar.gz
ちょっと拡張vcg-2003-12-31.tar.gz- let rec!! scheme と ML の狭間 letrec.ml
derive-y-combinator.scm- 再帰的な Variant 型で再帰型を模倣。 counter.ml←これじゃ 型エラーなのでこうする→counter2.ml
scheme では再帰型を許すのでさっくり書ける counter.scm- mutable transparency.ml
- ocaml-3.07 が出てきたところで、 ocaml-3.06 の中身をじっくりみてみた。次はもちろん 3.07 を 見てみたいんだけど、このツール使えるかなぁ。ocamlXML.ml
ocamlのソースを食わせるとなぞな XML を吐く。そのまえにビルドが大変.....。
関連するツール OcamlFunctionViewer.jar, Web Start Version- 簡単なリスト操作。高水準なプロセス起動!! commit_known_files.ml
いまいちファイルのネーミングが良くない。
cvs管理下で現在のディレクトリないのファイルで修正されたファイルを commit する。つまりまだcvsに追加されていないファイル(Unknown)の commit を避ける。- 無意味に hello world hello.ml
- ocaml をダウンロード、ビルドする。中途半端〜。gui-*.tar.gz の中の http.ml url.ml などが必要 update_ocaml.ml
- Thread.delay と signal sig_and_sleep.ml
- HTMLの木構造の繰返し構造を見つけるための第一歩。ちょっとやってみたバージョン。HTMLの パーズもしている。 tree-2004-03-23.tar.gz
- connect でブロックするのを避ける。 nonblock.ml
以下Unixのconnectと割り込みに関しての記事とかメモ
Unix connect() and interrupted system calls まだ読んでません
w3mは接続できない時にすぐにエラーを返すけど,lynxではそうではない- char2line.ml
- そういえば epochから 2^30秒たってしまったのでした。これに影響されてしまった。。。(汗) ocamlのintの最大値は 2^30-1。ポインタと整数を見分けるGC用のタグに1ビットと符合に1ビット つかっているから(signed)
float_of_int((int_of_string "1073946492") - (9*60*60)) なんてやってました (汗)
対処。 (float_of_string "1073946492") -. (9.0 *. 60.0 *. 60.0) あはは- labltkをしるにはTkのmanをダウンロードするのがいいのかぁ。Frx_after.idle は Tk の after idle に対応している。man after で説明が見られる。 tk_idle.ml
- ひさびさに書く。2年前の書きかけプログラムを完成させてみた。内容が同じファイルを一行にまとめて表示する samefile.ml
- 繰り返しをみつける。find_repetition.ml
- コンパイル出来ないプログラム。format4とは!? printf_test.ml
- ディレクトリ比較 & できるだけマージ merge_dir.ml
- Last modified: 日付 の部分を見つけて最終更新時刻を得る get_date.ml
- helloというテキストしか返さないHTTPサーバー。helloserver.ml
- ocaml-ssl (http://savonet.sourceforge.net/wiki/Savonet) を使ってみる (なくなった?) sslwget.ml
- helloというテキストを返すCGI hello_cgi.ml
- ファイルの比較 cmp.ml
- Talk Master IIの録音データのファイル名のつけ直し sort_timerrec.ml