Today アクセスカウンター Yesterday アクセスカウンター

ホワット・ア・ワンダフル・ワールド

私は知識に何ものかを付け加え,また他の人々がより多くのものを付け加える手助けをした --- G.H.ハーディ

全記事一覧 << 2008/07 12345678910111213141516171819202122232425262728293031 2008/09 >>

プロフィール

あろは (alohakun)

  • Author:あろは (alohakun)
  • 若槻俊宏 (WAKATSUKI toshihiro)

    連絡先 : alohakun ___at___ gmail.com
    mixi : http://mixi.jp/show_friend.pl?id=182927
    twitter : http://twitter.com/alohakun

    abstract

    プログラミングという人間の知的行為を体系化し,単なる職人芸ではなく,サイエンスにするための研究をしています.

    具体的には,等価変換計算モデルに基づいた,仕様記述からのプログラム合成の研究をしています.

    もっと噛み砕くと,プログラムの正しさをどのように定式化し,どのような枠組みで,どのように変換を進めていけば,正しさを保証したまま,効率的なプログラムを手に入れることができるのか,ということについて研究しています.

    キーワード : equivalent transformation, computation model, programming paradigm, formal specification, program synthesis













    あわせて読みたい


    この日記のはてなブックマーク数


    スカウター : ホワット・ア・ワンダフル・ワールド


    Map









    FC2 BLOG RANKING

FC2カウンター

ブロとも申請フォーム

この人とブロともになる

ホーム

OCaml で文字列からの read-eval-print

2006/12/12(火) 10:53:19

yoriyuki さんからコメントをいただきました.

> 文字列を eval したり,型情報を取得したりするやりかた

Toplevelというモジュールが標準でインストールされています。秘密のAPIなのでドキュメントはtoplevel.mliのコメントしかありませんが。

うほっ… そんな魅惑的なモジュールが.

しっかし,toplevel.mli なんてファイルはどこにも見当たらない… orz

というわけで,ソースを落としてきて,toplevel といういかにもそれっぽいディレクトリを漁ってみると… ありました.toplevel/toploop.mli というインタフェーイスファイルが.


val execute_phrase : bool -> formatter -> Parsetree.toplevel_phrase -> bool
(* Execute the given toplevel phrase. Return [true] if the
phrase executed with no errors and [false] otherwise.
First bool says whether the values and types of the results
should be printed. Uncaught exceptions are always printed. *)

(* Hooks for external parsers and printers *)

val parse_toplevel_phrase : (Lexing.lexbuf -> Parsetree.toplevel_phrase) ref


わはは,いかにもインターナルな香りが.大人の階段の〜ぼる〜.
そして,テキトーに grep してみると,stdlib/lexing.mli に,Lexing.lexbuf とやらを作る感じのアレが.


val from_string : string -> lexbuf
(** Create a lexer buffer which reads from
the given string. Reading starts from the first character in
the string. An end-of-input condition is generated when the
end of the string is reached. *)


そしてそれを標準出力にプリティプリント,あるいは文字列として取得するためには,stdlib/format.mli の


val std_formatter : formatter;;
(** The standard formatter used by the formatting functions
above. It is defined as [formatter_of_out_channel stdout]. *)

val stdbuf : Buffer.t;;
(** The string buffer in which [str_formatter] writes. *)

val str_formatter : formatter;;
(** A formatter to use with formatting functions below for
output to the [stdbuf] string buffer.
[str_formatter] is defined as [formatter_of_buffer stdbuf]. *)

val flush_str_formatter : unit -> string;;
(** Returns the material printed with [str_formatter], flushes
the formatter and resets the corresponding buffer. *)


ここらへんを使えばよさそう.

ふむ.なにやら道具は揃った感じ.でも使いかたがイマイチわからんので,テキトーに拾ったキーワードでぐぐってみたら,こんなジャストな話題が OCaml の ML :-) で出てた.

John Goerzen asked and Clément Capel answered:

> I am moving from Python to OCaml and one of the things I miss is
> Python's eval() call. It takes a string representing a bit of Python
> source code, evaluates it, and returns the result. I would like to be
> able to do similar things with OCaml.
>
> I have observed that /usr/bin/ocaml, the interactive top-level, is
> itself written in OCaml, which suggests that this should be possible.
> Although I have tried to study the source for this, it seems extremely
> complex and I can't figure out a way to do the simple evaluation
> described above.
>
> Can anyone help me out here?

Try this simple example:

Toploop.initialize_toplevel_env();;

let eval txt = let lb = (Lexing.from_string txt) in
let phr = !Toploop.parse_toplevel_phrase lb in
Toploop.execute_phrase true Format.std_formatter phr;;

eval "let add1 x = x +1;;";;
eval "add1 2;;";;

(compile with toplevellib.cma)

But be careful, it can break the typing system.
if you use the Toploop module in the
"string parameter" of the function eval or if you
evaluate it in the toplevel.
But it seems there's a guard with the new version (3.07+2).

わははは,ここまでくると,もはやタイプシステムも風前の灯火である (笑) objmagic よりも酷い.
というわけで,さっそく試してみた.
ようこそ… トップレベルの世界に…


$ ocaml
Objective Caml version 3.09.2

# Toploop.initialize_toplevel_env();;
- : unit = ()
# let eval txt = let lb = (Lexing.from_string txt) in
let phr = !Toploop.parse_toplevel_phrase lb in
Toploop.execute_phrase true Format.std_formatter phr;;
val eval : string -> bool =
# eval "let add1 x = x + 1;;";;
val add1 : int -> int =
- : bool = true
# eval "add1 2;;";;
- : int = 3
- : bool = true


むふふ,これと lablgtk を使えば,OCaml をマクロ言語に使うテキストエディタが簡単に作れそうだ.素晴らしすぎる.

というか,よく Ruby は eval があるから高速化が難しいとかどうのこうの,って議論があるけど,OCaml と同じように,「eval は使うと 8 年寿命が縮む… (空八命弾) くれぐれも使用には慎重になるのだぞ.御利用は計画的に」 ってノリにすれば良いのではないか ?

いくら Ruby が動的言語って言っても,クラスベースなんだから,C++ 的な静的ディスパッチもかなりの部分でできそうな気がするし.

まぁ,Ruby が eval 使いまくりなのは,結局のところマクロが無いからなんだけど. あと,型推論は部分的にやっても微妙なのかもしれない.

ちなみに,上のやりかたはタイプシステムにビッグイシューがあるし,ランタイムにもいろんな問題があるかららめぇーふつうにだめー ☆ らしい.ボウズ,悪いこたぁいわねぇ… タイプセーフな MetaOCaml 使っとき… らしい.

Dynamically evaluating OCaml code
John Goerzen asked and Basile Starynkevitch answered:

> I am moving from Python to OCaml and one of the things I miss is
> Python's eval() call. It takes a string representing a bit of Python
> source code, evaluates it, and returns the result. I would like to be
> able to do similar things with OCaml.

As observed by others, there is a big typing issue around this (what
would be the type of the eval function)?

If you really need something, you could hack the toplevel (at your own
risk). I don't think it is a good idea, unless you did very well
understood what you really want to do.

However, the functional values are usually enough to avoid the "eval",
and an "eval" won't be really safe.

Also, you could use metaocaml, which provide constructs (inspired by
eval) to typefully meta-program, ie generate programs at runtime in a
rather safe manner.

See http://www.cs.rice.edu/~taha/MetaOCaml/ for more.

dynamics (like old work from Leroy & Mauny - see X.Leroy's publication
pages on http://cristal.inria.fr/~xleroy ) and runtime type
information (like in Jun Furse GCaml) might also help - and are in
some remote way a bit related to eval's typing.

In addition to typing issues, there is also a runtime issue: dynamic
code generation really requires garbage collection of executable code,
which is not available in Ocaml (and would be terrible to implement -
it would mean rewrite most of the system)

あと,何やら興味深げ.今ちょっと時間が無いから,後で読む.

However, for the beginner, the good answer (at least as given by Ocaml
gurus here) to the usual "I want eval" request is simply "no you don't
really need it"


Issac Trotts asked and Basile Starynkevitch answered:

Issac Trotts wrote:
> Basile Starynkevitch wrote:
> > However, for the beginner, the good answer (at least as given by Ocaml
> > gurus here) to the usual "I want eval" request is simply "no you don't
> > really need it"
>
> That being so, how would you use OCaml as an extension language for a C
> program?

I'm not sure to understand your point. Many applications coded in C
embed Ocaml inside. The simplest way is to give the application a
compiled ocaml bytecode file (which can be choosen at runtime) invoked
thru ocaml_main

See section 18.7.4 Main program in C of
http://caml.inria.fr/ocaml/htmlman/manual032.html

An alternative is to have the application being a custum ocaml
program, with lots of C primitives. This means that the ocaml runtime
system has the control and invoke appropriately the C primitives
provided by the application.

If you ask about embedding the ocaml toplevel into your application,
it is a different question. I agree that extending or embedding or
customizing the toplevel is not very well documented.

どうやらトップレベルはアンドキュメントだから,トーシロが触るもんじゃねぇ… あんたのケースなら,C から OCaml を使う方が,たぶん良いぜ,ということらしい.
OCamlTB:0CM:0 このエントリーを含むはてなブックマーク | livedoorクリップ livedoorクリップ BuzzurlにブックマークBuzzurlにブックマーク newsing it!

lablgtk はじめるにき

2006/12/10(日) 14:38:29

lablgtk の API は,もはや Gtk とは別物なような… Ruby とかの素朴なバインディングとは異なり,名前も,呼び出しかたも独自.

OCaml:lablGTK

まぁ,そのぶん,異常にソースが簡潔になるわけなんですが.C であんなにタラタラ書いてたのが馬鹿馬鹿しくなりますな.とりあえずインラインでコールバックを書ける (クロージャ渡せる) のが素晴らしすぎる.あと型推論万歳.OCaml のコンパイルの時のエラーメッセージはけっこうわかりやすい気がする.

以下,ソース.型推論初心者にありがちな,型が合わないからとりあえず () 返しとけ !! OCaml 小学生にありがちな,とりあえず let 〜 in しとけ !! lablgtk の API がわかんなかったらとりあえず変数をグローバルにしとけ !! 的ななげやり感が随所に見えてほほえましいですね.


(* vim: set encoding=utf8:
コンパイル方法 :
$ ocamlopt -w s -I +lablgtk2 lablgtk.cmxa gtkInit.cmx edit.ml -o edit
$ ./edit
*)
open GMain
let window = GWindow.window ()
let vbox = GPack.vbox ~packing:window#add ()
let toolbar = GButton.toolbar ~packing:vbox#pack ()
let notebook = GPack.notebook ~packing:vbox#pack ()
let create_new_buffer () =
let scrollwin = GBin.scrolled_window ~width:300 ~height:300 ~packing:notebook#append_page () in
GText.view ~packing:scrollwin#add ()

let init_editor_window () =
window#connect#destroy ~callback:Main.quit;
let tooltips = GData.tooltips () in
let b = GButton.tool_button ~stock:`ADD ~packing:toolbar#insert () in
b#set_tooltip tooltips "新しいバッファを作ります" "" ;
b#connect#clicked ~callback: (fun () -> create_new_buffer (); ());
window#show ()
let _ =
init_editor_window ();
create_new_buffer (); (* たぶん,この間の一瞬のもたつきが見えちゃってる *)
GMain.main ()


vim のいい加減な OCaml モードでダンプしたもの (要 UTF8 保存.というか,OCaml で UTF8 が素直に通るとは思わなんだ.素晴らしい ← 英語圏で作られた処理系を信用しなさすぎ).

# 追記 : ブログ上でコメントを書き足した時に,全角スペースが入ってた… orz (uim を設定してなかった… というか,全角スペースぐらいちゃんとパースして欲しいのう (ムチャ))

なんか,起動した時に,一瞬もたつくのが気になる.OCaml に特有の現象なのか,俺のコードが葛すぎるのかは今後の調査が待たれるところです (他人事) たぶん,(show_all 相当の API が見付からなかったんだけど),ウィジットが作られるたびに show されてるから,一瞬残像が残るのだろうと思う (普通は,全部オブジェクト作ってから show するんだけど… lablgtk の API がよーわからんのじゃ).

ocaml_edit0.png


今回はガワだけしか作ってません.ボタンを押すと,新しいバッファが開くだけ.まだ何も実用的な機能は実装されていません.まぁ,サンプルコードが Web 上に少な過ぎるので,こういうのをちょこちょこ公開してみるだけでも,微妙に誰かの役に立つかもしれないし,誰も興味を持たないかもしれない (OCaml,Gtk,なおかつ資料が少ない独自 API というマイナー三重苦 !厳しすぎる !!)

参考文献

GTK+ 2.0 Tutorial using Ocaml (Gtk のチュートリアルを,まんま OCaml + lablgtk に翻訳したもの.よくやるわ…)
lablgtk リファレンス (2.4.0 なのでちょっと古い)
あと,ソースの中のサンプル (lablgtk-2.6.0/examples) (これが一番素晴らしい)
OCamlTB:0CM:6 このエントリーを含むはてなブックマーク | livedoorクリップ livedoorクリップ BuzzurlにブックマークBuzzurlにブックマーク newsing it!

抽象構文木をダンプしたい

2006/12/09(土) 18:02:00

なんとなく,ボクも OCaml の抽象構文木をダンプしたくなりました.

[Camlp4] 最適化

しかし,OCaml 小学生なので,さっぱり勝手がわかりません.

テキトーにぐぐるってみたところ,なんとなく parsing/printast.ml みたいな素敵げなモジュールを見付けたので,ここらへんを使えば良いのではないかと.

しっかし,これって標準添付じゃないよね ? Debian の apt で OCaml の追加パッケージを入れようとするとき,いつもどれがどれに入ってるのかさっぱり謎で躊躇してしまう.

# XML 処理がやりたくて xml-light とかいうのがちょうどパッケージにあった (libxml-light-ocaml-dev) から使ってみたんだけど,なぜか -I +xml-light しても "Unbound module Xml" とかいうエラーが出てコンパイル通らなかったよ… 明らかに /usr/lib/ocaml/3.09.2/xml-light/xml-light.cmxa とか存在してるのに… そこにある cmxa とか cmx とか全部読み込ませても駄目げだった.

そんなこんなでまぁ,とりあえず雰囲気でもつかもうかと,コンパイラに吐かせてみた.

てすとそーす

let f x = x + 1

let _ = Printf.printf "%d\n" (f 10)

実行結果


$ ocamlc f.ml
$ ./a.out
11

$ ocamlc -dparsetree f.ml
structure_item (f.ml[1,0+0]..f.ml[1,0+15])
Pstr_value Nonrec

pattern (f.ml[1,0+4]..f.ml[1,0+5])
Ppat_var "f"
expression (f.ml[1,0+6]..f.ml[1,0+15]) ghost
Pexp_function ""
None

pattern (f.ml[1,0+6]..f.ml[1,0+7])
Ppat_var "x"
expression (f.ml[1,0+10]..f.ml[1,0+15])
Pexp_apply
expression (f.ml[1,0+12]..f.ml[1,0+13])
Pexp_ident "+"


なんかエライ見にくいな… XML か何かで出力して欲しい (それも微妙).

他にもいろいろなオプションがあるようだ.undocument とかで,dump lambda と dump rawlambda の違いが謎.


$ ocamlc -dlambda f.ml
(setglobal Lambda!
(let (f/57 (function x/58 (+ x/58 1)))
(seq (apply (field 1 (global Printf!)) "%d\n" (apply f/57 10))
(makeblock 0 f/57))))

$ ocamlc -drawlambda f.ml
(setglobal Lambda!
(let (f/57 (function x/58 (+ x/58 1)))
(seq (apply (field 1 (global Printf!)) "%d\n" (apply f/57 10))
(makeblock 0 f/57))))

$ ocamlc -dinstr f.ml
branch L2
L1: acc 0
offsetint 1
return 1
L2: closure L1, 0
push
const 10
push
acc 1
apply 1
push
const "%d\n"
push
getglobal Printf!
getfield 1
apply 2
acc 0
makeblock 1, 0
pop 1
setglobal F!

$ ocamlopt -S f.ml
$ cat f.s
.data
.globl camlLambda__data_begin
camlLambda__data_begin:
.text
.globl camlLambda__code_begin
camlLambda__code_begin:
.data
.long 1024
.globl camlLambda
camlLambda:
.space 4
.data
.long 2295
camlLambda__2:
.long camlLambda__f_57
.long 3
.data
.long 1276
camlLambda__1:
.ascii "%d\12"
.byte 0
.text
.align 16
.globl camlLambda__f_57
.type camlLambda__f_57,@function
camlLambda__f_57:
.L100:
addl $2, %eax
ret
.text
.align 16
.globl camlLambda__entry
.type camlLambda__entry,@function
camlLambda__entry:
.L101:
movl $camlLambda__2, %eax
movl %eax, camlLambda
movl $camlLambda__1, %eax
call camlPrintf__printf_370
.L102:
movl %eax, %ebx
movl $23, %eax
movl (%ebx), %ecx
call *%ecx
.L103:
movl $1, %eax
ret
.text
.globl camlLambda__code_end
camlLambda__code_end:
.data
.globl camlLambda__data_end
camlLambda__data_end:
.long 0
.globl camlLambda__frametable
camlLambda__frametable:
.long 2
.long .L103
.word 4
.word 0
.align 4
.long .L102
.word 4
.word 0
.align 4


うん,全体的に,ほとんど gcc と同じだね.わかりやすい.

あと,本当に C と同等レベルなコードを出したかったら,-unsafe を指定すれば良いらしい.ただし,配列の境界とかをミスると SEGV るところまで C と同じになる.一切動的な安全性チェックが入らなくなるから.


■大堀先生の偉大さについて
(MLでは) 「バッファオーバフローなど、そもそもトピックですらない」



いや,SEGV ってくれるならば,まだマシな方か…


$ cat a.ml
let a = [|0; 1|]

let _ = Printf.printf "%d\n" a.(0);
Printf.printf "%d\n" a.(1);
Printf.printf "%d\n" a.(2)

$ ocamlc a.ml
$ ./a.out
0
1
Fatal error: exception Invalid_argument("index out of bounds")

$ ocamlc -unsafe a.ml
$ ./a.out
0
1
6528


よくわからないけど,なんとなく配列の要素数を持ってるような感じの ccall caml_array_get_addr, 2 が, getvectitem という危なげな感じがするヤツに置き換わってるのかね.


$ ocamlc -dinstr a.ml
const 1
push
const 0
makeblock 2, 0
push
const 0
push
acc 1
ccall caml_array_get_addr, 2
push
const "%d\n"
push
getglobal Printf!
getfield 1
apply 2
const 1
push
acc 1
ccall caml_array_get_addr, 2
push
const "%d\n"
push
getglobal Printf!
getfield 1
apply 2
const 2
push
acc 1
ccall caml_array_get_addr, 2
push
const "%d\n"
push
getglobal Printf!
getfield 1
apply 2
acc 0
makeblock 1, 0
pop 1
setglobal A!

$ ocamlc -unsafe -dinstr a.ml
const 1
push
const 0
makeblock 2, 0
push
const 0
push
acc 1
getvectitem
push
const "%d\n"
push
getglobal Printf!
getfield 1
apply 2
const 1
push
acc 1
getvectitem
push
const "%d\n"
push
getglobal Printf!
getfield 1
apply 2
const 2
push
acc 1
getvectitem
push
const "%d\n"
push
getglobal Printf!
getfield 1
apply 2
acc 0
makeblock 1, 0
pop 1
setglobal A!


というかそもそも,ML 様ともなれば,こんなあからさまなバグはコンパイルタイムに弾いてくれると思っていたのに.意外や意外.

負けない !! 僕等の gcc は,OCaml になんて負けない !!


# apt-get install libmudflap0 libmudflap0-dev

$ cat a.c
#include<stdio.h>
int a[] = {0, 1};

main() {
printf("%d\n", a[0]);
printf("%d\n", a[1]);
printf("%d\n", a[2]);}

$ gcc -g -fmudflap a.c -lmudflap
$ ./a.out
0
1
*******
mudflap violation 1 (check/read): time=1165646518.906926 ptr=0x8049b44 size=12
pc=0x4002e8ed location=`a.c:7 (main)'
/usr/lib/libmudflap.so.0(__mf_check+0x3d) [0x4002e8ed]
./a.out(main+0x19b) [0x804884f]
/usr/lib/libmudflap.so.0(__wrap_main+0x49) [0x4002e399]
Nearby object 1: checked region begins 0B into and ends 4B after
mudflap object 0x80c9df8: name=`a.c:2 a'
bounds=[0x8049b44,0x8049b4b] size=8 area=static check=4r/0w liveness=4
alloc time=1165646518.906806 pc=0x4002e33d
number of nearby objects: 1
0


ははは,見ろー 不正メモリアクセスがゴミのようだ ! gcc は OCaml よりもセキュアです !!

(参考文献 : BINARY HACKS pp.160-4)

いや,結局コンパイルタイムには弾けてないな… ごめんなさい,ML 先生 !!

というか,何もしなくても安全性を監視しててくれる OCaml の方があきらかに優れてるな.

結論 :

そもそも -unsafe を付けるのが根本的に間違ってる.
C/C++ プログラムは堅牢性に欠ける.OCaml は数理科学的でとても素晴らしい.




p4ck という,ステキ OCaml パッケージ集の中の,pa_bounds というのを使うと,配列境界を踏みこえてしまった場所をわかりやすく表示してくれるらしい.わーお,まったく素晴らしいね.

晩ごはんの履歴 2006-01-18 ■[Camlp4] p4ck インストールとかとか
晩ごはんの履歴 2006-03-15 ■[Camlp4] pa_bounds

… しっかし,まだ OCaml 小学生のボクは camlp4 に踏み込むべき時期では無いような気がするので,今回は静観 (というか,単にいろいろインストールするのが面倒なだけ).
camlp4 はハタチから !! あなたの移植性を損ねる恐れがあります.言語拡張は控えめに.
OCamlTB:0CM:2 このエントリーを含むはてなブックマーク | livedoorクリップ livedoorクリップ BuzzurlにブックマークBuzzurlにブックマーク newsing it!

LablGTK は素晴らしい

2006/12/09(土) 00:54:55

Common Lisp で Gtk を上手く使えなかったので,OCaml を使って見ようとちょっと思いつく.

別に Ruby とか Python みたいな P 言語でも良いのですが,個人的な信念により,私はネイティブコンパイラとインタラクティブインタプリタの両方を備えていない言語は,どうも片手落ちという気がして使う気になれないので (私の主用途では).そうなると,事実上,現状まともに使える言語は ML か Lisp に限定されてしまうという罠.

# じゃぁ,なんで C なんて使ってるの ? 惰性.あと Gtk Programming に Haskell を使うってのは,いろいろ微妙過ぎる気がする.

検索してみたところ,lethevert さんの素晴らしいチュートリアルが一発でヒットし,これはいけそうだ,という確信を得ました.

現在では,さらに簡単になっていて (ネイティブコンパイルをしないならば),以下のように一瞬でインストールできます.

(1) 本家から,OCaml のインストーラ ocaml-3.09.3-win-mgw.exe を拾ってくる.

LablGTK のサイト から,lablgtk-2.6.0-win32.zip と gtk-2.6.8-dlls-win32.zip を拾ってくる.

(2) OCaml をインストールする.標準では C:\Program Files\Objective Caml にインストールされるので,上の 2 つの zip ファイルを解凍して,中身 (bln, lib, etc などを,ディレクトリ構成を維持したまま全部マージする) をそこに移動する.

(3) スタブファイルをコンパイルする.

C:\Program Files\Objective Caml\lib\lablgtk2 に移動.

# 私は cygwin と MinGW 入ってるので,cygwin 上で移動した.

$ ocaml build.ml

とタイプするだけ.これでインストールは終了.

試しに Objective Caml/examples/lablgtk2 に移動して,

$ lablgtk2.bat testgtk.ml

とか打って見ると,ちゃんとウィンドウが開くことが確認できました.

ただ,ネイティブコンパイルして実行ファイルを作るのは,lethevert さんが試した時

>> lablgtk-2.4.0-ocamlwin-3.08.zip
>> Supports only bytecode linking (you need to compile from source for custom and native code.)

とは異なり,現在の lablgtk2 のバイナリは対応しているものの,上記した dlls の zip ファイルの中にはエクスポートライブラリ (*.lib) が入ってないので,別途持ってきてパスを指定してコンパイルする必要がある模様.

>> Supports both bytecode and native code, but you need the GTK+ export libs (not included with the above dlls) for native linking.

んな殺生いわんと,入れといてくれや〜 たいした容量じゃにゃいだろうに.そもそもどっからもってくるねん !!

LablGtk2-install.txt だけみると,まるで同梱されているような言い回しがされてるけど.

5) For custom linking or native code, you need to use the export libraries in the above DLL package. There is not default place to put them, so you should specify that at link time:
ocamlopt -ccopt "/link /libpath:/home/garrigue/gtk-2.6.8/lib"
-I +lablgtk2 lablgtk.cmxa gtkInit.cmx testgtk.ml -o testgtk.exe
or, on Mingw
ocamlopt -ccopt "-L/home/garrigue/gtk-2.6.8/lib" -I +lablgtk2 \
lablgtk.cmxa gtkInit.cmx testgtk.ml -o testgtk.exe
Again, if this fails you must make sure that your ocamlopt really works, and that all paths are correctly specified.

まぁ,今後の研究課題ということで.

# Gauche の時に作った win32 の Gtk コンパイル一式パッケージは,2.10.x とかだから流用できんしのう.面倒.

GLADE for Windows の Gtk+/Win32 Development Environment (runtime, devel, docs, glade, etc.) Installer 2.6.8-rc1 (.exe, 9.01M)

が流用できそうな気もする.これを適当にインストールして,lib/*.lib だけを取り出せば良さそう.だけど微妙なので,やっぱりソースからコンパイルした方が良いのかもしれない.




まぁ,別にいいや (現代の若者).バイトコードでも,P 言語よりは速いよ (たぶん).移植性が高まるかもしれないし (後付け).少し使い込んで,気に入ったら,それからネイティブコンパイルする方法を探しても全然遅く無いし.

それにしても,ML は素晴らしい.とりあえず hello, world.


open GMain

let main () =
let window = GWindow.window ~border_width: 15 () in
let button = GButton.button ~label:"hello, world!" ~packing: window#add () in
window#connect#destroy ~callback:Main.quit;
button#connect#clicked ~callback:window#destroy;
window#show ();
Main.main ()

let _ = Printexc.print main ()


いや,ML の M の字も知らない子なんで,文法とかはよくわからんのだけど (サンプルを書き換えて短くしただけ.というか,本家よりもサンプルコードが豊富なような.examples 以下にいっぱいあります).

とりあえず,ローカル変数が使いたかったら, let 変数 = 式 in と書けば良いということはわかった (笑) 再帰的定義がしたかったら,let rec 変数 = 式 わかりやすいのう.

OCaml プログラミング入門




昔書いた Gtk のプログラムを OCaml に書きなおすのは面倒なので,C -> ML への逆コンパイラとかあれば良いのに,と思った (いろいろ間違ってる).

あと ML は,現在メジャーな言語の中で最もマイナー (名前だけ非常に有名) という微妙な位置付けな気がするので,せっかく作っても反応が薄いであろうことがアリアリと予想できます.

スルーされぢから

# いや,あきらかに Prolog の方がマイナーだな.というか,Prolog はもう死んだ言語.少なくとも純粋なのは.

そもそも,ML で拡張可能なエディタとかって作れるのだろうか ? OCaml に文字列からの eval ってあるの ? 型付けできないだろうから無理っぽい気がするけど.
いや,string -> () とかに限定すれば可能か.副作用中心で (もはや関数型でもなんでもない w)




ありゃ… しまった (Readme.windows).

Do *not* install the Mingw/MSYS development tools from www.mingw.org: these are not compatible with this Caml port (@responsefile not
recognized on the command line).





Debian だと,ネイティブコンパイルもとても簡単.

# apt-get install liblablgtk2-ocaml liblablgtk2-ocaml-dev

そして,上記の hello, world をネイティブコンパイルするためには

$ ocamlopt -w s -I +lablgtk2 lablgtk.cmxa gtkInit.cmx hello.
ml -o hello
$ ./hello

だけで良いらしい.-w s ってのは,複文中で () 以外を返す関数に対する警告を抑制するオプションらしい.これが無いと,異様に警告が出てびびる.

ちなみに,バイトコードコンパイルしたい場合は,ocamlc を使って,.cma と .cmo というライブラリの方をリンクするようにすれば良いみたい.cma や cmo は,動的にリンクできるというメリットがあるらしい

$ ocamlc -w s -I +lablgtk2 lablgtk.cma gtkInit.cmo hello.ml
-o hello

hello 程度じゃわかんないけど,ネイティブコンパイルの方が,若干コンパイルに時間がかかるけど起動が速い,バイトコードはコンパイルがやたら速いけど,若干起動に時間がかかるような.

まぁ,いくらバイトコードといえでも,Linux でコンパイルしたやつを Windows で動かすとかは無理なんだろうね.gtk が絡むから (たぶん)

あと,ここのサンプルコードが素晴らしすぎる.

とりあえず,ここまでのところ OCaml は非常に素晴らしい感じなので,今日からボクもらくだっこになって数理科学的にバグを撲滅していく所存であります.
OCamlTB:0CM:4 このエントリーを含むはてなブックマーク | livedoorクリップ livedoorクリップ BuzzurlにブックマークBuzzurlにブックマーク newsing it!

最近のコメント

リンク

このブログをリンクに追加する

最近のトラックバック

人生の残り日数

日本人男性の平均寿命は 28700日.

RSSフィード

カテゴリー