Doge log

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

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

0.92の新機能がキター!!
というわけで今回はword再びです。
wordをもう少し詳しくやろうと思います。

Word

Factorのwordは関数、または手続です。
wordはユニークな名前を持ち、処理するコード(body)を持ちます。
またwordはmeta-dataを持たせることができます。
word自身はクラスでwords vocabularyに定義されています。

wordは以下の要素から構成されています。

  1. wordの名前
  2. 所属しているvocabularyの名前
  3. 定義(実行された時の動作)
  4. property(document、他のmeta-dataを含む)

Wordの定義

実際、wordはどのように定義され、どのように実行されるのでしょうか。
wordの定義には以下2つのアプローチがあります。

  1. wordをparseした時
  2. wordを実行した時

多くの場合はparse時に定義しますが、実行時に定義することも可能です。

wordがvocabularyのslotにメンバとして登録されることをinternedといいます。
(Lispの影響大な気がするなあ)

word自身はword、CREATEなどでも作成することができます。
ですがこれはwordを作るのみで実行は持ちません。

複合文からの定義

複合文の定義は名前と実行された時に処理されるquotとセット、つまり連想配列ような形になります。
複合文をparse時に定義するには: wordを使います。

: は名前と定義を引数にとります。
: は;が出てくるまでparseしてwordを定義します。
: で作成したwordは現在のvocabularyに定義されます。

Wordの命名規則

Factorではある程度命名規則を決めています。
代表的なものあげるとこんな感じです。

  • foo? booleanが返る
  • ?foo 条件を入れてその結果を返す
  • fooを作成
  • foo* fooの別実装。generic wordでよく用いられます
  • (foo) fooの詳細な実装
  • with-foo dynamic-scopeで使用します

Stack Effect

wordを定義する時には何を、何個引数にとって何を返すかを定義します。
それをStack Effectと呼んでいます。
inputとoutputを -- で区切って記述します。

: foo ( x y -- z ) + ;

foo wordは引数2つとり結果を1つ返します。
基本的にスタック指向の場合は引数、返り値はスタックから取る、積むだけです。
そのため多値を返したい場合など特別なことをせずそのままスタックに積むので非常にシンプルです。

GENERIC: M: HOOK:

引数のobjectによって振る舞いを変えたいwordを作りたい場合はGENERIC: M:
wordを使用します。

USING: arrays ;

GENERIC: foo ( obj -- )

M: array foo "Array" write ;

M: object foo "Object" write ;

{ } foo
"Array"
"A" foo
"Object"

GENERIC: wordは引数によって振る舞いを変えたいwordを定義します。
インターフェイスみたいなものを思ってもらってもいいです。
この例ではfooをgeneric wordと定義しています。

M: wordはmethodを定義します。
methodはgeneric wordと対で使用します。
methodは引数の型によって実行する定義を切り替えてくれるクラスです。
M: wordはクラス、generic word、実行部を引数にとります。

上記の例では配列の場合には"Array"、その他の場合には"Object"を出力します。

HOOK: wordはGENERIC: wordと似ていますが変数の型を見て振舞を変えます。
SYMBOL:、M: と共に使われます。
HOOK:はGENERIC:に更に変数を追加した形で定義します。

USING: arrays ;

SYMBOL: obj

HOOK: foo obj ( str -- )

M: array foo
"Array " write ;

M: object foo
"obj " write ;

{ } obj set
"A" foo
"Array"
"" obj set
"A" foo
"obj"

このように変数objの値を見て動作を切り替えます
GENERIC: M: HOOK:が読めればドキュメントもかなり読めるようになります。
この機構はxxxx protocolを実装する際に使われています。
配列もVectorも文字列もsequence protocolを実装していますが、これらは
sequence vocabularyに書かれているGENERIC:を実装しているのです。
(実装しているwordはは命名規則通り(xxx) や xxx*で実装しているはずです)

word property

wordは内部にhashtableを持っていてそこにdataを埋めこむ事ができます。
wordのpropertyにアクセスにするwordは以下です

  • word-prop ( word name -- value )
  • set-word-prop ( word value name -- )
  • word-props ( word -- props )
  • set-word-props ( props word -- )

持っているpropertyを具体的に説明すると大変なので割愛します。

とりあえずざっくりと説明しました。
次回はやっと制御構文(ifとか)をやります。

0.92が近いので内容が古くなりそうで心配だなー。
既にaccessorもニュースタイルになってるし。
継承もちょっと変わってるし、パターンマッチングとかもできるようになるしな。