🔙 Back to Top

Thu Feb 28 01:59:35 JST 2013

F#のパイプライン演算子、関数合成演算子

gosh> (define (>> f g) (.$ g f))
gosh> (define (sq x) (* x x))
gosh> (define (inc x) (+ x 1))
gosh> (define f (>> inc sq))
gosh> (f 3)
16
Prelude> let (>>) f g = g . f
Prelude> let sq x = x*x
Prelude> let inc x = x+1
Prelude> let f = inc >> sq
Prelude> f 3
16
Prelude> let g = inc >> sq >> inc
Prelude> g 3
17
gosh> (define g (>> (>> inc sq) inc))
gosh> (g 3)
17

いや、これはあかんでしょ.

gosh> (define-syntax >>
(syntax-rules ()
  ((_ f g) (.$ g f))
  ((_ f g h ...) (>> (.$ g f) h ...)) ))
gosh> (define g (>> inc sq inc))
gosh> (g 3)
17

それより、ついつい

gosh> (define-syntax >>
(syntax-rules ()
  ((_ f g) (.$ g f))
  ((_ f g ...) (>> (.$ g f) ...)) ))

と書いてしまう.まだまだ慣れが足りない. しかし、それでも何かしら定義は出来て、そうすると

gosh> (define g (>> inc sq inc))
gosh> (g 3)
18

となった.これは一体なんだ? << wakaran

Prelude> let (|>) x f = f x
Prelude> 2 |> inc |> sq |> sq
81
gosh> (define-syntax \>
(syntax-rules ()
  ((_ x f) (f x))
    ((_ x f g ...) (\> (f x) g ...)) ))
gosh> (\> 2 inc sq sq)
81

Schemeで | は使えない.へんちくりんな変数名を | で括るから.

gosh> (define |"| 1)
|"|
gosh> |"|
1

Haskellみたいなの方が、コードが少なくなるのは知ってるんだよ. まあ、どうせ趣味で使うんだから、その時々で好きなの使えばいいんだ.

もしかしてと思ってできたけど、.$は別に引数2つに限ってなかった. そうか、LISPのLISPたる所以は、引数はたいていいくつでもいいんだ. listをapplyしてるのが正しい形なんだから.

つまり、+という演算子は、Haskell含めてたいていは二項演算子だけど、 LISPだと、 (+ 1 2 3 ...) というのが当たり前

gosh> (define h (.$ sq sq inc))
gosh> (h 2)
81

gosh> (define (>> . ls) (apply .$ (reverse ls)))
gosh> (define i (>> sq sq inc))
gosh> (i 2)
17

gosh> (define (\> x . ls) ((apply >> ls) x))
|\\>|
gosh> (\> 3 sq inc)
10

この \> は、>> が関数だからこそ定義できた.

define-syntaxは長くなるから嫌だな.define-macroってのもあるみたい だけど、引数の数でmatchさせるようには出来てないみたいだし、 正直に言えば、LISPのマクロはなにがそんなにすごいのか分かってないです. 引数の評価を遅らせる版の関数で、あとcase-lambdaみたいなことができる、 くらいにしか.

Thu Feb 28 11:08:28 JST 2013

日記・ガベコレ

そうそう、学校の課題でGCを実装した.調べたりで構想ができるまでに 2日くらいかかったけれど、実際のコーディングは5時間程度で、デバグ まで出来た. 「世界初の記念すべきGCアルゴリズムはマークスイープGC[1]です. はじめて世に出てから半世紀近くが経過した今も、様々な処理系で 用いられている偉大なアルゴリズムです.」---(「ガベージコレクション のアルゴリズムと実装」中村成洋/相川光 共著 より)

長さ2000くらいの配列を延々と確保させてそれをゴミにするような プログラムを動かす.初めはヒープの上に配列を上から作っていって、 残りが2000未満になったら、mark and sweep を行う.残り、というのは ヒープの限界 - ヒープレジスタ値 で計算する.mark sweepはヒープ上のゴミオブジェクトをゼロで塗りつぶす 作業.本当はフリーリストとして持っておくんだけど.でもこの作業の 後、ヒープレジスタ値は変わらない.だって、そうでしょう

         heap
  0 --+---------+
      | object  |
      +---------+
      | garbage |
      +---------+
      | object  |
      +---------+
      | object  |
reg_h-+---------+
      |         |
      |  empty  |
      :         :
limit +---------+

reg_hの値は、heapの上からつめていって、(一番上をゼロとして、アドレスが 増える方向を下としてる)、空なスペースの一番上のアドレスとしている.

mark and sweep をすると、先のヒープはこうなる.

         heap
  0 --+---------+
      | object  |
      +---------+
      |  empty  |
      +---------+
      | object  |
      +---------+
      | object  |
reg_h-+---------+
      |         |
      |  empty  |
      :         :
limit +---------+

ほら、間に空白が空いただけで、reg_hは変わらない. だから、先の計算では、ヒープの残り容量は変わらないことになる. 従って、先ほど確保しようとしてGCを起こさせた配列確保を再び しようとすると、またGCを起こす.またmark and sweep する.地味に 時間がかかる.まるで使い物にならない.

改良方法はいくらでも思いついたが、残念ながらヤル気が起きない. それよりも、コンパイラ自体を書きなおしたい.少なくともOCamlとかいう 言語以外で.

Thu Feb 28 19:16:20 JST 2013

node.js vs SpiderMonkey

node.js は、というか V8 は、いつになったら、 javascript 1.7やそれより上に対応するんだろうな.

三年前のフォーラム記事.V8はJavaScriptじゃなくてECMAScriptに従う、と. ECMAScriptなんて、誰も知らないよ.

ちょっと書き捨てるのには、SpiderMonkey を使うにしても、 node.js は捨てれないしな.

function tarai(x,y,z){
    return x<=y? y
               : tarai(tarai(x-1,y,z), tarai(y-1,z,x), tarai(z-1,x,y))
}
print(tarai(13,6,0));

こんなものを、node.jsとSpiderMonkeyで実行してtimeを比較する. もちろんnode.jsではprintの代わりにconsole.logを用いる.

nodeがnode.jsであり、jsはSpiderMonkey.

cympfh@sazanami:~/test$ node --version
v0.6.12

cympfh@sazanami:~/test$ js -h
JavaScript-C 1.8.5 2011-03-31
usage: js [options] [scriptfile] [scriptarg...]
Options:
  -h            Display this information
  ()

cympfh@sazanami:~/test$ time node tarai.js
13

real    0m1.008s
user    0m0.980s
sys     0m0.020s
cympfh@sazanami:~/test$ time node tarai.js
13

real    0m0.993s
user    0m0.972s
sys     0m0.012s
cympfh@sazanami:~/test$ time node tarai.js
13

real    0m1.028s
user    0m1.012s
sys     0m0.012s
cympfh@sazanami:~/test$ time js tarai.js
13

real    0m9.148s
user    0m9.137s
sys     0m0.004s
cympfh@sazanami:~/test$ time js tarai.js
13

real    0m9.099s
user    0m9.085s
sys     0m0.004s
cympfh@sazanami:~/test$ time js tarai.js
13

real    0m9.209s
user    0m9.197s
sys     0m0.004s

ちょっと、違いすぎてビビった. これは、やっぱり、SpiderMonkeyは使いたくなくなる.

で、違う言語を持ち出しちゃうけど、

cympfh@sazanami:~/test$ time gosh test.scm
13

real    0m4.423s
user    0m4.056s
sys     0m0.020s

やっぱり、node.js使うことにしよう.