Doge log

Abby CTO 雑賀 力王のオフィシャルサイトです

アホが書き散らすFactor入門 その4

富山ブームきてますね。あの展開は...
で今回はvocabulary。
モジュールシステムという方がわかりやすいかな。

vocabularyとは

ユニークな名前を持ったwordの集まりです。
簡単に言ってしまえばライブラリモジュールです。
Factorは結構な量をFactor自身で書かれており、大量のvocabularyを読みこんで動作しています。

vocabularyはloadするとglobal領域にあるHashtableに格納されます。
一度読みこまれたvocabularyは明示的にreloadしない限り使いまわれます。

vocabularyを使ってみる

ではvocabularyを使ってみましょう。

USE: vectors
0 .s
V{ }

vectorクラスはvectors vocabulary内にあります。
vectorクラスを使うにはvectors vocabularyをloadしなくてはいけません。

一般的にvocabularyをloadするには

  1. USE:
  2. USING:

上記のwordを使います。

USE:はvocabularyひとつを引数に取ります。
複数のvocabularyをloadしたい場合にはUSING:を使います。

USING kernel vectors hashtables
io
;

USINGは;で終わるまで書かれているvocabularyを読み込みます。
読み込まれたvocabulary内のwordは現在のvocabularyに読み込まれ呼び出せるようになります。
デフォルトのvocabularyは"scratchpad"です。

また現在使用しているvocabularyはシンボル useで見ることができます。
.で出すと大量に出るので.sで見ます。
(正確にはparser vocabularyで定義しているのシンボルuse)

use get .s
V{ ~hashtable~ ~hashtable~ ~hashtable~ ~hashtable~ ~hashtable~...

shadowing word問題

wordは基本的にユニークな名前でないといけません。
では読みこんだvocabulary内wordと同じ名前のwordを定義するとどうなるのでしょうか。

USE: vectors
: "Hello" ;
0 .s
V{ }

Vectorクラスを生成するwordです。
上書きしているようですが、実際にはvectors::が呼ばれています。
また処理順を入れ替えてみると

: "Helo" ;
USE:
:1
Note: (scratchpad ) shadowed by (vectors )

なんだか警告がでますね。
(この状態でもvectors::が呼ばれますけど)
このように同じ名前のwordを読みこむと片方のwordを隠してしまいます。
隠されたwordを呼ぶにはIN: word
で明示的に現在のvocabularyを切り替える必要があります。

USE: vectors
: "Hello" ;
0 .
V{ }
IN: scratchpad
:1
Note: (vectors ) shadowed by (scratchpad )
0 .
0
"Hello"

切り替えるとちゃんと「隠してるwordがあるよ」と警告が出てきました。

上のようにIN: wordは現在のvocabularyを切り替えます。
ということはあるwordをあるvocabularyに定義するという事が出来ます。
vocabularyを作成する時にはIN: wordを使えばいいと気づくでしょう。
vocabularyの定義は後に説明します。

vocabulary loader

実際、vocabularyはどのようにloadされるのでしょうか。

vocabulary loaderはvocabularyがまだloadされていない場合、rootパスよりvocabulary名を元にファイルを読み込みます。
rootパスはシンボル vocab-rootsに入っています。

vocab-roots get .
V{ "resource:core" "resource:extra" "resource:work" "." }

resource:はFactorのresource、つまりFactorのインストールされているパスとの相対パスを表しています。

vocabulary名はそのままソースファイルとマッピングされています。
例えばfoo.barという名前のvocabularyであればソースファイルはfoo/bar/bar.factorに書かれています。

vocabularyを作成する

簡単なvocabularyを作成してみましょう。
今回はfoo vocabularyを作成してみます。
手順は

  1. directoryを作成
  2. ファイルを作成する
  3. ソースを書く
  4. loadする

といった流れになります。

directoryを作成

まずvocabularyのソースを置くdirectoryを作成します。
今回はfooという名前のvocabularyを作成するのでfooというdirectoryを作成します。

ファイルを作成する

次はソースファイルの作成です。
foo vocabularyなので先程作成したdirectory内にfoo.factorという名前のファイルを作成します。

ソースを書く

vocabularyのソースを書きます。
今回はシンプルなものにします。

IN: foo

: bar "Hello" ;

Helloを返すwordをひとつだけ定義します。

loadする

では作成したvocabularyをloadしてみます。

USE: foo
bar .
"Hello"

bar wordが呼び出せ、"Hello"が出力されるはずです。

とりあえずざっくりと説明しました。

Factorでプログラムを書くコツはワンライナーを書くようにする事です。
ワンライナーは1行で書けるように前後の入力を連鎖させます。
Factorは連鎖性言語なのでむしろこの考え方をしないといけないからです。
ワンライナーが得意な人は連鎖性言語をやってみると面白いかも知れません。

ツンデレ言語Factorシリーズ次回はstack shuffle wordをやる予定です。
(stackをいじれないとつらいので)