Nim
その朝も早起きしてインターネットしてたら、突然部屋の蛍光灯がチカチカ、そして消えちゃったよ。 そろそろ蛍光灯も寿命か? なんて考えていたら、パソコンの電池がヘタっているから、買ってね、ってご案内が 出てきた。天然UPSもちゃんとメンテしなきゃなんて思っていると、ネットに繋がらなくなった。
もうパソコン止めて、ごみ出しにでも行くか。台所の電気が点かず。これって、ひょっとして停電? 外は薄暗いも、かなたのアパートの防犯灯は点灯してた。停電、おいらの所だけ? それとも、 この集合住宅だけ?
ゴミを棄てに行く時、たまたま隣の人と遭遇。停電してません? ええ、してます。違う地域に 住んでる子供の友人に聞いたら、そちらも停電してるとか。そうすると広い地域で停電だね。
30分ほどして、防災無線から、広域停電してます。復旧の目処は立っていません。交通と火の元には 十分に注意して下さいってのが、流れてきたよ。そうか、朝食を作るのに、焚き火をするんで、 注意しろって御触れなんだな。納得。
おいらはとっくに朝食してるからいいけど、女房はトースターも使えずで困るだろうに。 ガスはプロパンだからいいけど、給湯器は使えんかった。女房は、この時とばかり、 フライパンで、フレンチトーストしてたぞ。
何時復旧するか分からん日でも、子供達は元気に登校してったぞ、と言うと、女房は、こんな日に 給食出るのかしらなんて言う。続けて、町内見回りに行ってきたらとも。
散歩をかねて出陣。信号消えてた。交通整理のおばさんが居たので、給食出るんですかねぇと、 聞くと、ああ、そこまで頭が回りませんでしたと。子供達に聞いてみた。今日はお弁当を持って 行くの? いいえ、違いますだって。 じゃ、今日は半どんだよって、さりげなくデマを流布。
駅に行ったら、真っ暗。駅長さんが出てきた、もうすぐ復旧します、ですって。電車を諦めて、 気動車(ディーゼル車)でも引っ張り出してきたの? それにしたって、信号系が駄目だろうに。 まてよ、昔ながらタブレットと言うかトークンで運用するんかな。 これの技術、プログラミングでクリティカルゾーンを実行する時にも、使われているからなあ。
幹線道路は、おまわりさんが、手信号で交通を捌いていた。ボランティアの人も出てた。 パーキングは、バーが開放されてて、停電時のフェイルセーフ設計が出来てた。 とあるスーパーでは、自家発電のエンジン音が聞こえた。
家に帰ると、女房はメタル電話改め光電話が駄目なんで、携帯で実家に連絡したと言ってた。 携帯のワンセグで、送電線が故障したって言ってた。防災無線は、相変わらず、停電してますとしか、言わない。 情報提供不足だな。
4時間程して復旧。ipadがネットに繋がらなくなった。パスワードが間違ってますだって。 パソコンは繋がる不思議な現象。ルーターにログインして設定を再確認したら、MACアドレスで 接続制限してるも、ipadのそれが洩れてた。設定して、セーブして無かったんだな。
機器は設定した後、一度電源を切り、コールドスタートして確認しておきましょうって言う、 鉄則を忘れていた、つけが回ってきた訳ですよ。それにしても、約2年間、停電もなく動かして きた、電力会社には敬意を払わなくていけないな。
ちなみに、送電線の相間ショートが、運用線とバックアップ線でほぼ同時に起こったとは、 マーフィな法則の再確認になりましたとさ。それにしても、線間が7メートル有るそうだけど、 落雪時のバウンドで、ショートまたは近接放電を起しただろう説が濃厚とか。 ああ、ギャロッピング現象 による停電の見解が出たな。送電線の迂回路が無かったのが致命的だな。インフラ設計は、 インターネットに学ぼうね。
今回の教訓として、パソコンは即シャットダウンしろ、水は出るうちに汲んでおけ。風呂水は、 トイレ水に出来るんで、満タンにしとけ。携帯やトランシーバーと言うか ゼネカバな受信器は、充電を怠らず。
Nim
次は何をやるかねぇ? HAXEなんてのも有るみたいだけど。こいつは オイラーの脳内キューにぶち込んでおいて、先に知ったNimからだな。
所でNimってどゆ意味? 盗む、くすねるってネガティブだなあ。まるでコピペ天国の あの国みたい。まてまて、ポジティブな意味もあるよーん。それはね、素早い、機知に富む とか、敏捷、融通の利くって意味もあるんだってさ。
総本家は、nimです。FreeBSDにも来てるかと思ったら、
[sakae@fb10 /usr/ports/lang/nimrod]$ cat pkg-descr Nimrod is a statically typed, imperative programming language that tries to give the programmer ultimate power without compromises on runtime efficiency. This means it focuses on compile-time mechanisms in all their various forms. Beneath a nice infix/indentation based syntax with a powerful (AST based, hygienic) macro system lies a semantic model that supports a soft realtime GC on thread local heaps. Asynchronous message passing is used between threads, so no "stop the world" mechanism is necessary. An unsafe shared memory heap is also provided for the increased efficiency that results from that model. WWW: http://nimrod-code.org/
nimの前身が、0.9.2って事で1年前にリリースされたようで、それ以降のやつは入って いませんでした。nimrodって、聖書に出て来てて、ニムロデ(狩猟の名人)、狩猟家 という意味らしい。
今は、0.10.2って事だから、名前を改めたって訳ね。Webを検索する時は古い名前も 対象にすると良い事があるかも知れないな。
入れ方は、zipファイルを落としてきて展開。中にあるbuild.shを走らせるだけ。数分すると、 bin/nimが出来る。後はPATHを通すだけ。Windowsを見据えて凝った事はしてない。
まてまて、install.shを覗いてみると、
"/usr/bin") bindir=/usr/bin configdir=/etc libdir=/usr/lib/nim docdir=/usr/share/nim/doc datadir=/usr/share/nim/data ;;
こんな事が書いてあるから、ばらばらに配置も出来るのね。それより興味深いのが、build.sh。 卒倒するような長さですよ。
何が長いって、それぞれのOS用について32Bitと64Bitでソースが分かれてて、 それ用にコンパイル方法が指定してありました。
2年1組は、Linuxの32Bit用、2年2組はLinuxの64Bit用と言った具合。FreeBSDの32Bit用は、 5年1組に入れられていたぞ。FreeBSD6.4の古いものでもちゃんとコンパイル出来たよ。
調子こいて、FreeBSD10にもいれようとした、gcc無いって言われた。build.sh内のgccをccに 変更。これでコンパイル出来た。次はハロワなんだけど、ここでもgccを要求された。しょうが ないので、nim.cfg内で、gccをclangに変更したよ。FreeBSDのデフォのコンパイラはclang だものね。
はろわ
世間並みにハロワしときます。
[sakae@fedora t]$ nim c -r hello.nim config/nim.cfg(45, 2) Hint: added path: '/home/sakae/.babel/pkgs/' [Path] config/nim.cfg(46, 2) Hint: added path: '/home/sakae/.nimble/pkgs/' [Path] Hint: used config file '/home/sakae/nim/config/nim.cfg' [Conf] Hint: system [Processing] Hint: hello [Processing] [Linking] Hint: operation successful (8755 lines compiled; 4.863 sec total; 9.973MB) [SuccessX] /home/sakae/t/hello Hello, Nim!
そして
[sakae@fedora t]$ tree . ├── hello ├── hello.nim └── nimcache ├── hello.c ├── hello.o ├── system.c └── system.o
nim語で書いたのが、C語に変換されて、それがgccでコンパイルされるとな。こういう方式は、 昔Schemeでやったな。えと、chickenとかGambit Scheme。あいつにらには、インタープリタとコンパイラが 付属してたけど、nimはどうよ?
[sakae@fedora t]$ nim i config/nim.cfg(45, 2) Hint: added path: '/home/sakae/.babel/pkgs/' [Path] config/nim.cfg(46, 2) Hint: added path: '/home/sakae/.nimble/pkgs/' [Path] Hint: used config file '/home/sakae/nim/config/nim.cfg' [Conf] Hint: system [Processing] lib/system/ansi_c.nim(38, 4) Error: cannot 'importc' variable at compile time lib/system/ansi_c.nim(39, 4) Error: cannot 'importc' variable at compile time lib/system/ansi_c.nim(40, 4) Error: cannot 'importc' variable at compile time lib/system/ansi_c.nim(151, 10) Error: cannot 'importc' variable at compile time lib/system.nim(2281, 6) Error: cannot 'importc' variable at compile time lib/system.nim(2283, 6) Error: cannot 'importc' variable at compile time lib/system.nim(2285, 6) Error: cannot 'importc' variable at compile time Hint: stdin [Processing] >>> echo("Hello NIM") Hello NIM >>>
実用になるかどうかは、分からんけどPythonみたいな雰囲気だな。
ついでに、nimのオプションを見とくと
[sakae@fedora t]$ nim --advanced Nim Compiler Version 0.10.2 (2014-12-29) [Linux: i386] Copyright (c) 2006-2014 by Andreas Rumpf Advanced commands: compileToC, cc compile project with C code generator compileToCpp, cpp compile project to C++ code compileToOC, objc compile project to Objective C code js compile project to Javascript rst2html convert a reStructuredText file to HTML rst2tex convert a reStructuredText file to TeX jsondoc extract the documentation to a json file buildIndex build an index for the whole documentation :
みんな大好きjs語にも変換出来るのね。
[sakae@fedora t]$ nim js hello.nim
これで、キャッシュの中に、hello.jsが出来上がった。オイラーは別に嬉しくも何とも ないけどね。まあ、時代が時代ですから、ブラウザーと言う仮想CPUのアセンブラーを 吐き出すのが今風なんでしょうな。
nimを書く為のemacsの設定
って、nimを書く為のvimの設定に倣った訳ではありません。あちらは、quickrun一発らしい ですけど。。。
nim-modeと、ac-nimも入れて補完完了。 設定は、
;; nim (setq auto-indent-on-visit-file t) ;; If you want auto-indent on for files (require 'auto-indent-mode) (add-to-list 'auto-indent-multiple-indent-modes 'nim-mode) (eval-after-load 'nim-mode '(add-hook 'nim-mode-hook 'ac-nim-enable))
後はquickrun対抗品。なんでもanyとかあるらしいけど、使いこなせないだろうから、 シンプルに、godocからの連句を作りました。nim-mode.elの最後にでも、コピペ。
(defun nim-run (query) "nim run on buffer *nim-run-output*" (interactive (list (buffer-file-name))) (unless (string= query "") (save-buffer) (start-process-shell-command "nim-run" "*nim-run-output*" (concat "nim c --hints:off -r " (buffer-file-name) " " (read-from-minibuffer "args: "))) (switch-to-buffer "*nim-run-output*") nil)) (defun nim-clear-screen () (interactive) (erase-buffer)) (define-key nim-mode-map (kbd "\C-c\C-r") 'nim-run)
nimble
nimbleって、nim用のパッケージ・マネージャだそうです。
インストールする時、libcryptoとlibsslが見つからんと言われたんで、それ用にリンクして 完了。
[sakae@fedora ~]$ nimble update Downloading package list from https://github.com/nim-lang/packages/raw/master/packages.json Done. [sakae@fedora ~]$ nimble list : csv: url: git://github.com/achesak/nim-csv (git) tags: csv, parsing, stringify, library description: Library for parsing, stringifying, reading, and writing CSV (comma separated value) files license: MIT website: https://github.com/achesak/nim-csv :
136個、登録されてた。Rustに比べてどうよ。物は試しにインストールしてみる。
[sakae@fedora ~]$ nimble install csv Downloading csv into /tmp/nimble_2133/csv using git... Initialized empty Git repository in /tmp/nimble_2133/csv/.git/ remote: Counting objects: 7, done. remote: Compressing objects: 100% (7/7), done. remote: Total 7 (delta 0), reused 3 (delta 0), pack-reused 0 Unpacking objects: 100% (7/7), done. From git://github.com/achesak/nim-csv * branch master -> FETCH_HEAD * [new branch] master -> origin/master HEAD is now at 6a982da Fixed inconsistent behavior and added skipBlankLast option. Fixes part of #1. Switched to a new branch 'origin/master' Installing csv-0.1.0 /tmp/nimble_2133/csv/documentation.html -> /home/sakae/.nimble/pkgs/csv-0.1.0/documentation.html /tmp/nimble_2133/csv/csv.nimble -> /home/sakae/.nimble/pkgs/csv-0.1.0/csv.nimble /tmp/nimble_2133/csv/csv.nim -> /home/sakae/.nimble/pkgs/csv-0.1.0/csv.nim /tmp/nimble_2133/csv/README -> /home/sakae/.nimble/pkgs/csv-0.1.0/README /tmp/nimble_2133/csv/LICENSE -> /home/sakae/.nimble/pkgs/csv-0.1.0/LICENSE /tmp/nimble_2133/csv/csv.nimble -> /home/sakae/.nimble/pkgs/csv-0.1.0/csv.nimble csv installed successfully.
nimbleにはinitコマンドなんてのが装備されてて、プロジェクトの開始時に使ってね、なんて 説明が有ったけど、具体的にはどうすればいいの? その答えが、 How I start Nimなんて所に載ってた。
nimbleで提供されるモジュールを作って、Nimを盛り上げようぜって方法の説明だった。 今なら提供数も少ないので、いろいろやると良いかも。gemやcpanみたいになっちゃっちゃ、 埋もれてしまいますから。
なにはともあれ、Nimへのとっかかりとしては、非常に良く出来たアーティクル。是非、手を 動かしてみたいぞ。せっかちな人は、 Learn X in Y minutes where X=Nimがよい。
nimbleから、strfmtを入れておくと、
import strfmt echo "Hello {} number {:04.1f}".fmt("World", 6.0)
こんな風に、フォーマット出力出来るようになるぞ。是非入れとけ。
スクリプトみたい
上記のフォーマット出力をnimで実行して、結果が得られるまでの時間を測ってみる。
[sakae@fedora z]$ time nim c -r hoge.nim config/nim.cfg(45, 2) Hint: added path: '/home/sakae/.babel/pkgs/' [Path] config/nim.cfg(46, 2) Hint: added path: '/home/sakae/.nimble/pkgs/docopt-0.1.0' [Path] config/nim.cfg(46, 2) Hint: added path: '/home/sakae/.nimble/pkgs/strfmt-0.5.5' [Path] config/nim.cfg(46, 2) Hint: added path: '/home/sakae/.nimble/pkgs/csv-0.1.0' [Path] config/nim.cfg(46, 2) Hint: added path: '/home/sakae/.nimble/pkgs/nimble-0.6.0' [Path] config/nim.cfg(46, 2) Hint: added path: '/home/sakae/.nimble/pkgs/' [Path] Hint: used config file '/home/sakae/nim/config/nim.cfg' [Conf] Hint: system [Processing] Hint: hoge [Processing] Hint: strfmt [Processing] Hint: macros [Processing] Hint: strutils [Processing] Hint: parseutils [Processing] Hint: unicode [Processing] Hint: math [Processing] Hint: times [Processing] Hint: fenv [Processing] Hint: unsigned [Processing] Hint: pegs [Processing] Hint: streams [Processing] [Linking] Hint: operation successful (17962 lines compiled; 4.507 sec total; 24.250MB) [SuccessX] /home/sakae/z/hoge Hello World number 06.0 real 0m4.540s user 0m1.248s sys 0m3.171s
strfmtは裏でいろいろなソースに展開してんのね。結構時間がかかった。二回目からは、 必要な部分だけコンパイルされるので、早くなる。
: /home/sakae/z/hoge Hello World number 006.54 real 0m1.059s user 0m0.503s sys 0m0.505s
もっと早くならないの? そんなせっかちな人は、Tiny C Compilerを gccの代わりに使えばよい。それ用のドライバーと言うか、スクリプターは、次のようにする。
[sakae@fedora z]$ cat nimhs #!/bin/sh nim --cc:tcc --verbosity:0 -d:release -r c $*
これを使って、hoge.nimを、スクリプトのように実行してみる。
[sakae@fedora z]$ time ./nimhs hoge.nim Hello World number 006.54 real 0m0.972s user 0m0.219s sys 0m0.727s
二回目の実行は
[sakae@fedora z]$ time ./nimhs hoge.nim Hello World number 012.35 real 0m0.782s user 0m0.285s sys 0m0.480s
まるで、型落ちしたパソコンで、Pythonスクリプトを実行してるみたい。
debug
情けない事に、もしもの為のdebug方法を見とく。例にそのものずばりが出てた。
[sakae@fedora examples]$ cat -n debugging.nim 1 # Simple program to test the debugger 2 # compile with --debugger:on 3 4 proc someComp(x, y: int): int = 5 let a = x+y 6 if a > 7: 7 let b = a*90 8 {.breakpoint.} 9 result = b 10 {.breakpoint.} 11 12 proc pp() = 13 var aa = 45 14 var bb = "abcdef" 15 echo someComp(23, 45) 16 17 pp()
フラグを付けてコンパイルしたやつを走らせると、debuggerに落ちてくれるんだろう。多分。
*** endb| examples/debugging.nim(17) debugging *** *** endb| >>h *** endb| list of commands (see the manual for further help): GENERAL h, help display this help message q, quit quit the debugger and the program <ENTER> repeat the previous debugger command EXECUTING s, step single step, stepping into routine calls n, next single step, without stepping into routine calls f, skipcurrent continue execution until the current routine finishes c, continue, r, run continue execution until the next breakpoint i, ignore continue execution, ignore all breakpoints BREAKPOINTS b, break [fromline [toline]] [file] set a new breakpoint for line and file if line or file are omitted the current one is used breakpoints display the entire breakpoint list toggle fromline [file] enable or disable a breakpoint filenames list all valid filenames DATA DISPLAY e, eval <expr> evaluate the expression <expr> o, out <file> <expr> evaluate <expr> and write it to <file> w, where display the current execution point stackframe [file] display current stack frame [and write it to file] u, up go up in the call stack d, down go down in the call stack bt, backtrace display the entire call stack l, locals display available local variables g, globals display available global variables maxdisplay <integer> set the display's recursion maximum *** *** endb| >>c *** endb| reached examples/debugging.nim(8) someComp *** *** endb| >>bt examples/debugging.nim(17) debugging examples/debugging.nim(15) pp examples/debugging.nim(8) someComp : *** endb| >>l *** endb| Frame (4 slots): result = 6120 x = 23 y = 45 a = 68 *** endb| >>q
これだけ使えれば、十分かな。詳しくは、 Embedded Nim Debugger (ENDB) User Guideを参照の事。 ついでに、プロファイラーもって事なら、 Embedded Stack Trace Profiler (ESTP) User Guide
まてまて gdbでも試験しておくか。
[sakae@fedora z]$ cat -n fuga.nim 1 var x = 12345 2 for i in 1 .. 3: 3 echo(i) 4 echo(x)
[sakae@fedora z]$ nim --lineDir:on --debuginfo c fuga.nim [sakae@fedora z]$ gdb -q ./fuga Reading symbols from ./fuga...done. (gdb) b fuga.nim:3 Breakpoint 1 at 0x8061431: file /home/sakae/z/fuga.nim, line 3. (gdb) run Starting program: /home/sakae/z/fuga Missing separate debuginfos, use: debuginfo-install glibc-2.20-7.fc21.i686 Breakpoint 1, fugaInit () at /home/sakae/z/fuga.nim:3 3 echo(i) (gdb) c Continuing. 1 Breakpoint 1, fugaInit () at /home/sakae/z/fuga.nim:3 3 echo(i) (gdb) p i_88018 $1 = 2 (gdb) p x_ x_88004 x_getpostn x_putbytes x_putlong x_destroy x_inline x_putint32 x_setpostn (gdb) p x_88004 $2 = 12345
変数名は、gdbに推測させる事。どうやら、変数名_12345 みたいのが、それみたい。
こうしてdebugが完了したら、リリース。早く動かす方法と、サイズを小さくする方法が トリックとして挙げられていたぞ。
Q. Which option to use for the fastest executable? A. For the standard configuration file, ``-d:release`` does the trick. Q. Which option to use for the smallest executable? A. For the standard configuration file, ``-d:quick --opt:size`` does the trick.
一応、確認してみるか。題材は前回のWebに出てた、各種言語のベンチ
[sakae@fedora z]$ cat fib.nim proc fib(n: int): int = if n < 2: return n return fib(n - 2) + fib(n - 1) echo(fib(42))
普通にコンパイルすると
[sakae@fedora z]$ time ./fib 267914296 real 0m37.644s user 0m37.331s sys 0m0.187s
今度は、スピード優先でコンパイル
[sakae@fedora z]$ nim c -d:release fib.nim [sakae@fedora z]$ time ./fib 267914296 real 0m2.049s user 0m1.999s sys 0m0.043s
爆速になりましたと、メディアが好む宣伝文句を一応、の賜わってみます。
そして次は、小さくなーれの呪文を唱えてみます。
[sakae@fedora z]$ nim c -d:quick --opt:size fib.nim [sakae@fedora z]$ time ./fib 267914296 real 0m8.599s user 0m8.552s sys 0m0.014s [sakae@fedora z]$ size n.fib fib text data bss dec hex filename 125440 424 5716 131580 201fc n.fib 14659 308 4000 18967 4a17 fib
元が小さいので(go比ですけど)、余り嬉しくないな。
訳あり
爆速の理由は何処にあったんでしょうか? と、これまたTV屋が好むキャッチャー句を 並べてみます。
手がかりは、オプションで指定した、-d: に有りだな。releaseを付けると、各種チェックが 省略された上に、最適化が行われるとな。最適化で何十倍も速くなるってのは、ちと信じられないので、 各種チェック(と言う余計なお世話、もとえ、有り難い、小言)が、幅を効かせているんだろうな。
nim.cfgにこんな事が書いてあった。@ifは#ifの代わりね。#はコメント記号として使っているから。
@if release or quick: obj_checks:off field_checks:off range_checks:off bound_checks:off overflow_checks:off assertions:off stacktrace:off linetrace:off debugger:off line_dir:off dead_code_elim:on @end @if release: opt:speed @end
最適化を施して生成されたfib.cは、
N_NIMCALL(NI, fib_88003)(NI n) { NI result; NI LOC5; NI LOC6; result = 0; { if (!(n < 2)) goto LA3; result = n; goto BeforeRet; } LA3: ; LOC5 = 0; LOC5 = fib_88003((NI32)(n - 2)); LOC6 = 0; LOC6 = fib_88003((NI32)(n - 1)); result = (NI32)(LOC5 + LOC6); goto BeforeRet; BeforeRet: ; return result; }
こんな具合に、すっきりサッパリしてるのに対して、チェックが入って安全側に振って あるやつは、ここに表示し切れないぐらい、いろいろな事をやってたぞ。
結局、十分に虫取りしたら、監視コードは削除した上で、野に放つって訳だな。 これって、子供が親の保護を受けて成長し、自立してくのと一緒の事だな。これから、 社会の荒波に向かって船出するみなさん、頑張ってくらはい!
Nim on Rosetta Code
Nimなページに、Nim on Rosetta Code なんてのが出てた。
ロゼッタ・ストーン って古代の記録なのね。解読したものが、日本語になってた。 ロゼッタストーン/日本語訳とその解説
人間が喋る言語は、数千あるそうだけど、どんどん話者がいなくなって、衰退していって るそうな。
コンピュータ言語は、次々に生まれて、死ぬのも速い。記録を残しておこうってんで、 コンピュータ言語用のロゼッタストーンが用意された。Nimも将来に備えて、登録して あるんだな。
遺跡言語にならないように、頑張って話者を増やしてください。オイラーも応援しますよ。