Doge log

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

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

こんな事やってる場合じゃないんだけど。
しっかし富山ブームですなあ、ホント。

とりあえずインスコまでは割と楽なFactorですが、実際、プログラムを書くにして
も覚えなければいけない事がたくさんあります。
その辺Factorはシンプルな言語なので覚える事は割と少ないと思います。
予約語なども少ないのですが覚えなくてはいけないテクニックは多そうです。
(テクニックというよりは連鎖性言語に慣れるだけなのかも知れません)

シンタックス

基本的には空白をtoken扱いしているだけです。
また大文字小文字を区別します。
なので

2 x + .
2 X + .

では違がう式です。
コメントは

  1. ! 行末までコメント
  2. #! 行末までコメント(Shellから呼ぶ用かな)

です。

リテラルですが代表的なものを抜粋して書いてみます。

  • Number

普通に数値を書きます。

1
-1

基本的に型はintegerになります。
特殊な奴らもいます。BIN,OCT,HEXです。

  • BIN 0,1のバイナリとして扱う

BIN: 100 .
4

  • OCT 8進数として扱う

OCT: 20 .
16

  • HEX 16進数として扱う

HEX: FF .
255

  • Ratio

Lispなんかでもありますが/で割った型です。

1/20
76/33

これはこのままの形です。
Floatに展開されるような言語だと?となりますがうまく動作します。

1/2 2 * .
1
1/3 2 * .
2/3

  • Float

いわゆる少数点を持った数値です。

10.5
.5
7.e13
1.0e-5

あと虚数も扱えるのですが割愛します。
あとwordのリテラルもイマイチわからなかったので次回にまわします。

  • Quotation

Quotationは括弧[ ] で囲まれたブロックです。
Quotationは実は無名関数です。
実際callで呼ぶと実行されます。

[ 1 2 3] call .s
1
2
3

callで3つの値が積まれます。
FactorはLispの影響を受けています。
Lispのlambdaでletを書く(実際に中身は別だろうけど)ような感じです。
値などを局所的に保持したりもできます。
(with-scopeで)
後、Quotationはsequenceも実装しています。
なのでQuotationはsequenceの操作も可能です。
その辺はおいおいやっていこうと思います。

  • Array

配列は{ } で囲みます。

{ 1 2 3}

配列なのでサイズは固定です。
可変長なものを使いたい場合は Vectorを使います。

可変長なリストです。
配列の先頭にVをつけるとVectorになります。

V{ 1 2 3 }

似たようなものにByte Array、Bit Arrayがあります。

! Byte Array
B{ }
! Bit Array
?{ }

  • String

"(ダブルクォート)で囲むとStringになります。

"Hello World" .

Stringはsequenceを実装しているのsequenceの操作も使えます。
ちなみにCharはCHAR:を使います。

CHAR: a .
97

Stringは一度定義すると固定長のsequenceになります。
Stringを効率よく操作するためにはString Bufferを使います。

SBUF"Hello world"

Bufferなので実際に Stringにするには>string wordを使います。

SBUF"Hello world" >string .

  • Hashtable

連想配列です。
H{からはじまり、keyとvalueをさらに{で囲みます。

H{ { "foo" "value" } { "bar" "value } }

連想配列用の操作が使えます。
その辺はおいおい書こうと思います。

  • Tuple

FactorにもTupleがあります。
FactorのTupleはユーザ定義のclassを定義する際に使います。
classというよりはLispのdefstructに近いです。

T{ person name address phone }

ここではpersonという名前のclassを定義しています。
slotにname,address,phoneを持っています。
実際には名前とslotの間にdelegateを定義できるのですがまだよく
わかってないので後まわしです。

wordの定義の基礎中の基礎

Factorでは関数(式という方がいいかな)をwordと呼んでいます。
(この辺りはForthと同じ考え方だと思います。)
wordはコンパイルされvocabulary(モジュール)の辞書に登録されます。
wordは先頭にコロンで始まり、名前、式、そしてセミコロンで終わります。

: hello "Hello World!" print;

これは"Hello World"という文字列を出力するhelloというwordを定義した例です。
呼びだす際には

hello

とするだけです。
セミコロンまでがwordなのでこのように改行して書く方がいいかも知れません。

: hello
"Hello World"
print
;

wordは関数の位置付けなので引数をとる事ができます。
基本的にスタックの値を参照するのですが書き方の基本としてStack
Effectを宣言するようです。

Stack Effectは以下のように書きます。

: sq ( x -- y ) dup * ;

Stack Effectは( input -- output )のようにリストで書きます。
この例は引数の値(現在のStackの一番上)を2乗しています。
ここで出てきているdupというwordはスタックの一番上の値をコピーして一番上に積みます。
(スタックを操作するwordは他にもたくさんあるので徐々に紹介していきたいと思います。)
大体のStack Effectの書き方はexampleとして紹介されています。
代表的なものとして以下のような書き方をするようです。

  1. ? boolean
  2. elt sequenceの中のobject
  3. m, n integer
  4. obj object
  5. quot quotation
  6. seq sequence
  7. str string
  8. x, y, z number

基本的にinputとoutputの数はチェックされるようです。
とりあえず引数に何をとって何を返すのかが読めないとword、vocabularyドキュメントを読な
いのでここは覚えないといけません。

また余談ですがword内にwordを定義することも出来ます。

: a
: b "call b" print ;
;

ここではaの中でbを定義していますが、登録される辞書は同じなのでbを呼びだす事ができます。
scopeの話は後々しようと思います。

ここまで書いて思ったけど全然シンプルじゃない気がしてきたお!
ツンデレ言語だと思うお!
次のバージョンからlet, let*, named-parameterが入るっぽいのでもっととっつきやすく
なるといいなあ。