factor(2)

ニュートン誌のバックナンバーを見てたら、巨木の記事が出てた。それによると日本では、 地上高1.3mの所で幹回りが3mを超える樹が巨木と定義されてるようだ。

そんな樹なら近くの神社にいっぱいあるぞ。神社のスペック表によると、本社の社は京都に あって、そこからの出張所らしい。もう、この地に来てから1000年以上は経っているらしい。 そんな神社だからこそ、りっぱな樹があるのだろう。樹の種類はけやきだそうだ。

まいにち、境内を通っているのに、いままで知らなかったよ。C.W.ニコルさんの、『マザーツリー 母なる樹の物語』 だったかに倣って、樹の息を聞いてみよう。散歩の間の一休みに丁度良さそう。野鳥さんも 一杯来てさえずっているし、耳の保養にも良い所だから。

所で、幹回り3mってどれぐらい。直径1mぐらいだな。大人2人が手をつないでみて、つなげる ぐらいか。身体尺ですな。歩数も巻尺の変わりをするな。昔、伊能さんは、全国を歩いて 回って地図を作ったらしいけど、歩数が正確だからこそ出来た偉業らしい。

外国の王様はそういう事が出来ない為、指の長さをインチという単位で残したらしい。 フィートもヤードも身体尺。そんじゃ、もう一つの単位系、重さはどうだ。後世まで 重さを残すなら、王様の金玉を乾かしたものがいいな。ダイヤモンドの重さを測る単位は 豆の重さだったそうだから、金の重さを測るには金玉が最適。3金玉って、時価価値で 幾らぐらいになるんでしょうね?

金に縁のない人は、そんな事考えるな。時間の無駄だ。時は金也!

factorでApp製作

前回factorの資料をちらちら見てたら、factor語で書かれたソースを元にアプリが 製作出来るよって書いてあった。

factorは、factorって言うアプリとそれが参照するイメージ(Diskみたいにイメージしてね)が セットで動いている。そのイメージがまた大きいんだな。今、FreeBSDに入れてるのを確認 したら、63Mも有った。

これにfactor上のアプリ(テトリスとか)をsaveして、相手に配るってなると、例のiOSの アプリみたいになっちゃって、はなはだ具合が悪い。そこで、factorチームの人は、必要な ものだけを入れたイメージとそれを動かすVMを一まとまりにする事を考えた。 これなら何処でも動かせるって訳だな。

Windows7にもfactorを入れておいたので、Winの方でやってみる。

IN: scratchpad USE: ui.tools.deploy
IN: scratchpad "tetris" deploy-tool
IN: scratchpad Command: deploy
Loading resource:extra/tetris/tetris.factor
   :
Clearing megamorphic caches
Saving final image

これで、単独で動くtetris.exeが出来上がった。容量は1.8Mだったよ。

FreeBSDの方だと

( scratchpad ) USE: tools.deploy
( scratchpad ) "tetris" deploy
{
    "Tetris/tetris"
    "-i=/home/sakae/factor/temp/staging.math-threads-compiler-ui.image"
    "-resource-path=/home/sakae/factor/"
    "-run=tools.deploy.shaker"
    "-vocab-manifest-out=/home/sakae/factor/temp/vocab-manifest-tetris"
    "-deploy-vocab=tetris"
    "-deploy-config=/home/sakae/factor/temp/deploy-config-tetris"
    "-output-image=Tetris/tetris.image"
    "-pic=0"
}
Loading resource:basis/tools/deploy/shaker/shaker.factor
  :
Saving final image
Binary deployed to /home/sakae/factor/Tetris.

FreeBSDのfactorは時代が古いせいか、ファイルが2つに分かれていた。容量的にはWinとさほど 変わらず。

[sakae@pcbsd ~/factor]$ ls -l factor Tetris/*
-rwxr-xr-x  1 sakae  sakae   400362 Jul 12 10:40 Tetris/tetris
-rw-r--r--  1 sakae  sakae  1225776 Jul 12 10:41 Tetris/tetris.image
-rwxr-xr-x  1 sakae  sakae   400362 Jul  3 09:38 factor

これを見ると、deploy用にダイエットしたイメージを作っているのね。そして、factor本体と イメージを一つにするって進化があるのね。 Debian版では進化が有って、実行ファイルが一つだけになってた。

scaffold

かの有名なレールには、scaffold なんてのが付いていたように思う。Rails4になっても 健在なのかしらん? あちら方面にはすっかりご無沙汰だからなあ。

factorに付属してるemacsモジュールは、fuelって言うんだけど、こやつにも足場が付属 してる。ボキャブラリィーって言うモジュールって言うかアプリを開発する為の道具セットだ。 どんなのがあるかと言うと

fuel-scaffold-authors     fuel-scaffold-help        fuel-scaffold-platforms
fuel-scaffold-summary     fuel-scaffold-tags        fuel-scaffold-tests
fuel-scaffold-vocab

コードを書いたりヘルプを書いたりテストを書いたりが簡単に出来るようになってる。上で 見たdeployは、まあ稀な事だから出来ないけど。

新しいボキャブラリィーを作る時は、fuel-scaffold-vocabする。どんな名前にするかって 聞いてくるんで適当に名前を付ける。ああ、末代までこの名前が付いて回るんで、愛情 溢れる名前を付けてあげよう。

次は Vocab root: resource: って聞いてくるんで、workって応答。これで、work-dirの 中に、指定した名前のdirが作られて、その中に指定した名前.factorってファイルが出来る。 続けて、幾つが質問されるけど、付属ファイルの事だから後で指定してもいいし、雛形だけを 先に作っておいても良い。

今回は、factで行ってみる。

! Copyright (C) 2013 Your name.
! See http://factorcode.org/license.txt for BSD license.
USING: ;
IN: fact

: fact ( n -- n! )
         dup 0 =
         [ 1 ]
         [ dup 1 - fact * ]
         if
;

これで、C-c C-l して、コンパイルすると、文句を言われた。

Restarts:

:1 Use the kernel vocabulary
:2 Defer word in current vocabulary
:3 Load /home/sakae/factor/work/fact/fact.factor again

-----------
Press g go to file, 1-3 invoke restarts, q bury buffer

kernelをインクルードせいとな。インクルードのfactor方言はUSING なので、そこに 追加してく。

Note:
Already using ``kernel'' vocabulary
Loading /home/sakae/factor/work/fact/fact.factor
/home/sakae/factor/work/fact/fact.factor

9:          [ dup 1 - fact * ]
                     ^
No word named “-” found in current vocabulary search path

Error: condition

Restarts:

:1 Use the math vocabulary
:2 Defer word in current vocabulary
:3 Load /home/sakae/factor/work/fact/fact.factor again

今度は、引き算が無いとぬかす。math をUSING しろとな。嗚呼、マシンに使われてるな。 mathを追加したら、コンパイルが通ったので、いよいよ使うぞ。

IN: scratchpad USE: fact
:errors - show 1 compiler errors
IN: scratchpad :errors

==== /home/sakae/factor/work/fact/fact.factor

/home/sakae/factor/work/fact/fact.factor: 6

Asset: fact

The input quotations to “if” don't match their expected effects
Input              Expected       Got
[ 1 ]              ( ..a -- ..b ) ( x -- x x )
[ dup 1 - fact * ] ( ..a -- ..b ) ( x -- x )
:errors - show 1 compiler errors

今度は論理エラーですかい。6行目。期待値と実値を見比べると、あらら、スタックが 成長してるってさ。dropしとけばいいんだな。

IN: scratchpad 5 fact

--- Data stack:
120

やっと動いたよ。そんじゃ、順序が逆になるけどテストコードを書いてみる。

! Copyright (C) 2013 Your name.
! See http://factorcode.org/license.txt for BSD license.
USING: tools.test fact ;
IN: fact.tests

[ 24  ] [ 4 fact ] unit-test
[ 20 ] [ 5 fact ] unit-test

間違ったテストコードです。実行してみると、

IN: scratchpad "fact" test
Loading resource:work/fact/fact-tests.factor
Unit Test: { [ 24 ] [ 4 fact ] }
Unit Test: { [ 20 ] [ 5 fact ] }
--> test failed!
:test-failures - show 1 unit test failures

--- Data stack:
120
IN: scratchpad :test-failures

==== resource:work/fact/fact-tests.factor

resource:work/fact/fact-tests.factor: 8

Unit Test: { [ 20 ] [ 5 fact ] }

=== Expected:
20
=== Got:
120
[Traceback]

なる程、エラーの時はこんな風になるんだ。そんじゃ、引数を与えないで実行したらどうなる?

IN: scratchpad fact
Data stack underflow

Type :help for debugging help.
IN: scratchpad :help
datastack-underflow. ( obj -- )

Vocabulary
debugger

Error description
Thrown by the Factor VM if an attempt is made to pop elements from an empty data stack.

Notes
You can use the stack effect tool to statically check stack effects of quotations. See Stack effect checking.

Definition
IN: debugger
: datastack-underflow. ( obj -- ) "Data" stack-underflow. ;

Debugger commands:

:s    - data stack at error time
:r    - retain stack at error time
:c    - call stack at error time
:edit - jump to source location (parse errors only)
:get  ( var -- value ) accesses variables at time of the error
:vars - list all variables at error time

ふむ、:helpで、debuggerが起動してきた。データスタック、予備のスタック、コールスタック っていう構成で動いているのね。面白そうなんで、コールスタックを覗いてみる。

IN: scratchpad :c
(U) Quotation: [ c-to-factor -> ]
    Word: c-to-factor
(U) Quotation: [ [ catchstack* push ] dip call -> catchstack* pop* ]
(O) Word: command-line-startup
(O) Word: listener
(O) Word: (listener)
(U) Quotation: [
        [ ~quotation~ dip swap ~quotation~ dip ] dip swap
        [ call datastack ] dip -> swap [ set-datastack ] dip
    ]
(U) Quotation: [ call -> datastack ]
(O) Word: fact
(U) Quotation: [ signal-handler -> ]
    Word: signal-handler
(U) Quotation: [
        OBJ-CURRENT-THREAD special-object error-thread set-global
        current-continuation -> error-continuation set-global
        [ original-error set-global ] [ rethrow ] bi
    ]

今の所、意味不! ソース嫁なんですかね。ちょっと調べてみる。ハンドブックに 困った時は、 helpかseeって書いてあったから。

IN: scratchpad \ :c help
:c ( -- )
Factor documentation > Factor handbook > The language > Exception handling > The debugger
Prev: :r ( -- )
Next: :get ( variable -- value )

Vocabulary
debugger

Word description
Prints the call stack at the time of the most recent error. Used for interactive debugging.

Definition
USING: accessors continuations namespaces prettyprint ;
IN: debugger
: :c ( -- ) error-continuation get call>> callstack. ;
IN: scratchpad \ :c see
USING: accessors continuations namespaces prettyprint ;
IN: debugger
: :c ( -- ) error-continuation get call>> callstack. ;

ふむ、helpの方が親切だな。こうして定義までもさっと見られるって、ほらsmalltalkっぽく ないかい。

データと言うか引数がスタックを渡り歩いてくる、それをforth用語で言う所のword、一般 用語で言うと関数で加工してくって見方をすれば、おいらにはパイプでいろいろ処理 してくように思えるぞ。

後、上のfactでもそうなんだけど、変数ってものがさっぱり顔を出さない。と言う事は 変数名についてあれこれ悩む必要無し。(悩み無用の・・・ なんてCMも有ったな)この辺はハスケラーさん達が有り難がる、 ポイントフリースタイルが、自然に実現されてるぞ。華麗もとえカリー化なんて機能も 備わっているしね。至れり尽くせりですよ。

そうそう、ワード名(関数名)を英字で始めなきゃいかんと言う変な制限も無いし、 記号文字を適当にワード名に混ぜ込んでもOK。こういう所は、Schemeチックだなあ。

App製作

折角factなんてのを書いたんで、強制的にAppにしてみる。Appに出来る条件としてMAINが 必要との事なんで、

USING: kernel math ;
IN: fact
: fact ( n -- n! ) dup 0 = [ drop 1 ] [ dup 1 - fact * ] if ;
MAIN: fact

と書いて、それを deployしてみた。

sakae@debian7:~/factor/fact$ ls -lh fact
-rwxr-xr-x 1 sakae sakae 1.2M Jul 12 16:42 fact
sakae@debian7:~/factor/fact$ ldd fact | wc -l
62

色々リンクしてますなあ。記念にobjdump -d したやつ

08080ef0 <start_standalone_factor>:
 8080ef0:       55                      push   %ebp
 8080ef1:       57                      push   %edi
 8080ef2:       56                      push   %esi
 8080ef3:       53                      push   %ebx
 8080ef4:       83 ec 6c                sub    $0x6c,%esp
 8080ef7:       e8 e4 b0 fd ff          call   805bfe0 <pthread_self@plt>
 8080efc:       8b bc 24 80 00 00 00    mov    0x80(%esp),%edi
 8080f03:       c7 04 24 9c 02 00 00    movl   $0x29c,(%esp)
 8080f0a:       8b ac 24 84 00 00 00    mov    0x84(%esp),%ebp
 8080f11:       89 c3                   mov    %eax,%ebx
 8080f13:       e8 68 ab fd ff          call   805ba80 <_Znwj@plt>
 8080f18:       89 5c 24 04             mov    %ebx,0x4(%esp)
 8080f1c:       89 04 24                mov    %eax,(%esp)
 8080f1f:       89 c6                   mov    %eax,%esi
 8080f21:       e8 2a 19 02 00          call   80a2850 <_ZN6factor9factor_vmC1Em>
 8080f26:       89 34 24                mov    %esi,(%esp)
 8080f29:       e8 32 db fd ff          call   805ea60 <_ZN6factor23register_vm_
:

実際に走らせてみると、、、

sakae@debian7:~/factor/fact$ ./fact
The die word was called by the library. Unless you called it yourself,
you have triggered a bug in Factor. Please report.
Starting low level debugger...
Basic commands:
  q ^D             -- quit Factor
  c                -- continue executing Factor - NOT SAFE
  t                -- throw exception in Factor - NOT SAFE
  .s .r .c         -- print data, retain, call stacks
  help             -- full help, including advanced commands

factorのBUGを踏んだか心配してくれてるよ。今回は確信犯ですから、何も言うまい。

less.el

emacs 24を使ってて、ふと less-minor-mode が無い事に気付いた。何か設定でも 必要なの? それとも他のモードに吸収されちゃの? 調べてみたけど分からんので elファイルが無いかと探ってみたよ。

そしたら、less.elなんて名前の ずばりのやつが出てきた。

易しくコードが書いてあって、勉強になるなあ。