« 2009年2月 | メイン | 2009年4月 »

2009年3月27日

Factorに入門する (11) apply combinatorsとcurry

くるくる回りながらも上昇していると信じたいFactorへの入門も11回目です。今回は、apply combinatorsとcurryでFactorがもつパワーの一端を感じてみます。

前回は、"xとyがnを法として合同か?"というwordをこんな風に定義しました。

: modEq? ( x y n -- ? ) swap over mod -rot mod = ; 

明らかに分かりづらいですよね。keepというcombinatorを使っても

: modEq? ( x y n -- ? ) [ mod ] keep swapd mod = ;

やはり分かりづらい。トリッキー。スタック操作にあたまを使いすぎている気が。 スタックベースの言語の限界か...? いや、そんなことはないはず。

このwordで本質的にやりたいことはなんなのか。それは"nとのmodをx, yのふたつに適用し、その結果が等しいかどうかを判定する" ことです。"mod nをふたつの値に適用する"ようなことができるcombinatorがあるでしょうか、調べてみましょう。

Apply combinators

The apply combinators apply a single quotation to multiple values.

これがつかえそうです。中でも

bi@ ( x y quot -- )
Applies the quotation to x, then to y.

これがまさにそうですね。9と8が2を法として合同か? と判断するなら[ 2 mod ] bi@とやればよいので

( scratchpad ) 9 8 [ 2 mod ] bi@

--- Data stack:
1      ! 9 2 modの結果
0      ! 8 2 modの結果
( scratchpad ) =

-- Data stack:
f
 

というふうにやればよいですね。さて、これをwordにしようとすると、引数としてわたされてくるn (この例でいえば、2)をどうやってquotationの中にいれるか? が問題です。前にとりあげたfried quotationを使ってもいいのですが、よりプリミティブな形であるcurryを使ってみます。

( scratchpad ) 9 8 2 [ mod ] curry 

--- Data stack:
9 
8
[ 2 mod ]
( scratchpad ) bi@

--- Data stack:
1
0

x [ p ] curry で [ x p ] が作られます。Haskellが流行ってからよく見かけるようになった「カリー 化」、スタックベースのFactorではこんなに単純なんです。で、これでmodEq? をかけます。

: modEq? ( x y n -- ? ) [ mod ] curry bi@ = ;

驚異的に分かりやすくなりました。nでmodする関数を作成し([ mod ] curry)、それを2つの値に適用し、それを比較する。ほぼ人間が考えるレベルの抽象度です。fried quotationでも書いてみます。

: modEq? ( x y n -- ? ) '[ _ mod ]  bi@ = ;

このくらい単純な例でも、こっちのほうが、読むひとにより易しいですね。

2009年3月26日

Factorに入門する(10) スタックを操作しまくる

Factorへの入門第10回。このあたりでわれにかえって、基本的なスタック操作のwordについてしらべます。

FactorはForthの末裔なのでスタックが重要です。Factorにはdata stack, retain stack, call stackの3つのスタックがあるようですが、ふつうに"the stack"というときはdata stackのことです。 Factorのwordはスタックからデータをとり、そしてスタックに結果を残します。これを"stack effect"といいます。 word定義にはstack effectを書くことができます。

: multiple? ( x n -- ? ) mod 0 eq ;

カッコ"()"で囲われた部分がstack effectの記述です。 "--"の左側が実行前、右側が実行後です。 このwordの場合は、スタックの上にある値2つ (xとn)をつかって、結果としてひとつの値をスタックにつみます。 xとnはこの順につまれています。つまり、nがスタックの一番上です。 このwordは、xがnで割り切れるかどうかチェックする関数になります。 modのstack effectは ( x y -- z )なので、特にスタックをいじる必要はありません。

では、"xとyがnを法としたときに合同かどうかチェックする"wordを書こうとおもったらどうでしょうか。rubyみたいな普通の言語で書くとこうですかね。

def modEq?(x, y, n)
	x % n == y % n
end

factorで書くとどうでしょう。stack effectは( x y n -- ? )にしましょう。まずは対話環境で考えてみます。

( scratchpad ) 9 8 2

--- Data stack:
9
8
2
( scratchpad ) 

ここで、9 mod 2 と8 mod 2の結果が欲しいわけです。2は2回使うのでコピーしておきたい。スタックトップの値を単にコピーするwordがあります。

( scratchpad ) dup

--- Data stack:
9
8
2
2

dupはForthから存在する由緒正しいwordです。PostScriptにもあります。stack effectは ( x -- x x )。明解ですね。では次に、沈んでいる8を取り出しましょう。これは、コピーを取り出さなくてもよいです。

( scratchpad ) rot

--- Data stack:
9
2
2
8
( scratchpad )

rotも由緒正しいwordです。stack effectは ( x y z -- z y x )。 スタックトップに8, 2がありますが、順序が逆なので交換しましょう。それからmodをとります。

( scratchpad ) swap

--- Data stack:
9
2
8
2
( scratchpad ) mod

--- Data stack:
9
2
0
( scratchpad ) 

swapのstack effectは ( x y -- y x )。続いて、9 2 0 の順序を0 9 2にしましょう。そこまでくればあとひといき。

( scratchpad ) -rot

--- Data stack:
0
9
2
( scratchpad ) mod

--- Data stack:
0
1
( scratchpad ) =

--- Data stack:
f
( scratchpad ) 

-rotは、スタックトップから3つの値をrotとは逆順にまわします。( x y z -- z x y )ですね。ここまでをwordにまとめてみます。

: modEq? ( x y n -- ? ) dup rot swap mod -rot mod = ; 

over ( x y -- x y x )を使うと、こう書くこともできます。1手少ない:-)

: modEq? ( x y n -- ? ) swap over mod -rot mod = ; 

いずれにしても、慣れないと判じ物ですね。慣れると、このくらいなら気にならなくなると思います。

Factorには、古典的なshuffle wordsのほかにも(たぶんJoy由来の)combinatorがあります。この例はdip combinatorでこう書くこともできます。

: modEq? ( x y n -- ? ) swap over mod [ mod ] dip = ; 

まずswap overでx n y nという使いやすい並びにしておき、modを実行してy mod nをスタックトップにおき、そしてスタックトップをretain stackにいれておいてx mod nを計算する([ mod ] dip)する、という流れです。

keepというcombinatorも使えます。

: modEq? ( x y n -- ? ) [ mod ] keep [ swap ] dip mod = ;

この場合は、まず[ mod ] keepで y mod nを計算し、その上にnをのせます。y mod n の結果をzと書くと、x z n。[ swap ] dip してz x nにして、modする、という流れです。

あ、swapdというshffule wordsがあるのを今発見。stack effectは( x y z -- y x z )で、[ swap ] dipと同じです。

: modEq? ( x y n -- ? ) [ mod ] keep swapd mod = ;

dip使う場合もswapd使うとこんなふうに書けます

: modEq? ( x y n -- ? ) dup [ mod ] dip swapd mod = ; 

でもkeep使うほうが短いですね。この例の場合、どうしてもnをコピーしなくてはいけません。そのためにdupやoverを使ってもいいのですが、keepを使えばnを使ったあとに戻してくれるので、dupやoverなどが不要になり、結果として短くかけるのですな。

さて、スタック上のデータを華麗に:-)扱うには、shuffle wordsはもちろんですが、combinatorも適宜駆使するのがきっとFactorらしいにちがいない。dip combinatorsはとりあげましたが、他のcombinatorも今後とりあげていきます。

2009年3月24日

Factorに入門する(9) マクロでFizzBuzz

Factor入門第9回。またFizzBuzzかよ。Factorは今時の言語なので、Lisp的なマクロがあります。

マクロの実例。

( scratchpad ) : ++ ( x -- x ) 1 + ;
( scratchpad ) 2 ++ .
3
( scratchpad ) MACRO: macro++ ( x -- x ) [ 1 + ] ;
( scratchpad ) 2 macro++ .
3
( scratchpad ) 

見た目は普通のword定義に似ています。違いは、quotationをかえすように書かなくてはいけないところ。実行結果はふつうのwordと同じ。

では何が違うのか? というと、

A call of a macro inside a word definition is replaced with the quotation expansion at compile-time if precisely the following conditions hold:
- All inputs to the macro call are literal
- The word calling the macro has a static stack effect
- The expansion quotation produced by the macro has a static stack effect
If any of these conditions fail to hold, the macro will still work, but expansion will be performed at run-time.

とのことで、入力がリテラル・マクロを呼ぶwordのスタックエフェクトがstatic・かつマクロが生成するquotationのスタックエフェクトもstaticのときに、コンパイル時に展開されるそうです。

さて、FizzBuzzをマクロで書き直してみます。friedバージョンを書き直しましょう。

IN: fizzbuzz
USING: macros kernel io math math.parser prettyprint sequences fry ;

: modN? ( x n -- ? ) mod 0 = ;
MACRO: fb ( x n str -- x/str )
    pick number?
    [ '[ _ dup _ modN? [ drop _ ] when ] ]
    [ '[ _ _ _ 2drop ] ]
    if ;

: pp ( x/str -- ) dup number? [ number>string ] when print ;
    
100 [ 1 + 15 "FizzBuzz" fb 3 "Fizz" fb 5 "Buzz" fb pp ] each

ま、これでも動くんですが、「引数がすべてリテラル」の条件が満たせてないので、速度のメリットもないですね。マクロについてはまた改めてとりあげようと思います。

Factorに入門する(8) dip combinatorsを駆使してFizzBuzzを書く

Factor入門第8回。今回は、Factorに多々あるcombinatorのうち、"dip combinators"について調べます。factorのcombinatorとは、combinatory logicでいうcombinatorのようなのですが、これを調べるのは、また後日。先に実例で理解しましょう。

ではdipです。documentの説明をみてみましょう。

The dip combinators invoke the quotation at the top of the stack, hiding the values underneath:

よくわからんですね。試してみましょう。

( scratchpad ) 1 2 3 [ / ] dip

--- Data stack:
1/2
3
( scratchpad ) clear
( scratchpad ) 1 2 3 4 [ / ] 2dip

--- Data stack:
1/2
3
4
( scratchpad ) 

dipは、「スタックトップのquotationを実行する。ただし、quotationの下にある値はいったんどけておき、quotation実行後に戻す。という動作をしています。dipのstack effectは( x quot -- x )となっていますが、この"x"がどけておく値ですね。

2dipの場合は、quotationの下にある値2つをどけています。この「どけておく先」を、factorでは"retain stack"といっているようです。

さて、前回にひきつづきFizzBuzz。dipをつかって書き直してみます。

IN: fizzbuzz
USING: kernel io math math.parser prettyprint sequences fry ;

: modN? ( x n -- ? ) mod 0 = ;
: fb ( x n str -- x/str )
    pick number?
    [ pick [ modN? ] 2dip ? ] [ 2drop ] if  ;
   

: pp ( x/str -- ) dup number? [ number>string ] when print ;
    
100 [ 1 + 15 "FizzBuzz" fb 3 "Fizz" fb 5 "Buzz" fb pp ] each

前回とはword fb見た目がまったく違います。よりシンプルですが、pickして2dipして?、って流れは、ちょっと考えないとおいて行かれます。fried quotationに比べるとトリッキーな感じです。

このコード例はこの記事にそっくりなのは偶然、ではなく、先にカンニングしていたからです。

FizzBuzzを最初に書いた後、他に書いてるひとはいないかな? と思って探してみつけました。しかしその時点では2dipが分からなくて読めず。ようやく、自力で2dipがつかえるところに辿り着きましたよ。

Factorに入門する(7) Fried QuotationでFizzBuzzを書く

流浪のFactor入門第7回。本日は、"fried quotation" についてです。

Fried quotationとは何か? ドキュメントをみてみましょう。

The fry vocabulary implements fried quotation. Conceptually, fried quotations are quotations with "holes" (more formally, fry specifiers), and the holes are filled in when the fried quotation is pushed on the stack.

fried quotationとは「穴」があいているquotationで、スタックにpushされたときに、その穴が埋められるものをいいます。fried quotationは " '["からはじまります。「穴」は"_"または"@"です。実例をみてみましょうか。

( scratchpad ) 4 '[ _ 1 + ]

--- Data stack:
[ 4 1 + ]
( scratchpad ) 30 15 '[ _ _ mod ]

--- Data stack:
[ 4 1 + ]
[ 30 15 mod ]

"_"がスタック上の値で穴うめされているのが分かります。

( scratchpad ) 2 [ sq ] '[ @ . ] call
4

"@"は、"_ call"のsyntax sugarだそうです。上の例では、[ sq ] call になっているわけですね。

fried quotationはcurryとかcomposeより便利な手段、だそうなので、本来は先にcurryとかcomposeをみるべきなのかもしれません。次回の宿題です。

さて、前回たどたどしいFizzBuzzをかきましたが、fried quotationで書き直してみます。

IN: fizzbuzz
USING: kernel io math math.parser prettyprint sequences fry ;

: modN? ( x n -- ? ) mod 0 = ;
: fb ( x n str -- x/str ) pick number?
    [ '[ _ dup _ modN? [ drop _ ] when ] call ]
    [ 2drop ]
    if ;
: pp ( x/str -- ) dup number? [ number>string ] when print ;
    
100 [ 1 + 15 "FizzBuzz" fb 3 "Fizz" fb 5 "Buzz" fb pp ] each

fried quotationを濫用しすぎな気がしますが( "'[ _ _ _ 2drop ]"とか酷いな)、これ便利だな。

(2009.3.24 9:59) 無意味なfried quotationがあったので直しました

2009年3月23日

Factorに入門する(その他) はじめてのFizzBuzz

素直にFizzBuzzを書いてみました。

IN: fizzbuzz
USING: kernel io math prettyprint sequences ;
: fizzBuzz ( -- ) "FizzBuzz" print ;
: fizz ( -- ) "Fizz" print ;
: buzz ( -- ) "Buzz" print ;
: modN? ( x n -- ? ) mod 0 = ;

: fizzBuzzMain ( array -- ) 
    dup 15 modN?
        [ drop fizzBuzz ]
        [ dup 3 modN?
            [ drop fizz ]
            [ dup 5 modN?
                [ drop buzz ]
                [ . ]
              if
            ]
          if
        ]
    if ;

100 [ 1 + fizzBuzzMain ] each

かっこわるい。xがnで割り切れるならstrをスタックに置く、みたいなwordが書ければよいんだけど、手持ちの語彙でシンプルに書くことができません。まだまだFactor使いの初歩にもいっていないなわたし。

2009年3月19日

Factorに入門する(6) 簡単なスクリプトを書いてみる

帆も櫂もないFactor入門第6回。前回深みにはまったparsing wordsのことはひとまず忘れます。

ここまで、対話環境であるlistenerで遊んでいるだけだったのですが、ここで簡単なスクリプトを書いてみました。題材はどう書く? orgから17歳教。生年月日を入力すると、17歳とXヶ月X日と表示するスクリプトです。

エラー処理皆無。"Factorらしい"書き方とか全然できていなさそうですが。

USING: kernel math.parser calendar math io ;
IN: age17code
: duration>monthsInInteger ( duration -- x ) duration>months >integer ;
: getDaysPart ( duration -- x ) dup duration>monthsInInteger months time- duration>days >integer ;
: whenAge17 ( timestamp -- timepstamp ) 17 years time+ ;
: age17duration ( timestamp -- duration ) whenAge17 now swap time- ;
: age17and ( timestamp -- months days ) age17duration dup duration>monthsInInteger swap getDaysPart ;

"生まれた年は? (西暦で): " write flush
readln string>number
"生まれた月は?: " write flush
readln string>number
"生まれた日は?: " write flush
readln string>number
<date> age17and
! stack: months days
swap number>string
"あなたは17歳と" write write "ヶ月" write
number>string write "日です" print

書いてみての発見。

  • 対話環境だと読み込まれているvocaburaryでもスクリプトには宣言しないとダメ。USING: kernel ;も必要なのか!
  • word定義するときには、IN:しておかないとダメ。へー。
  • write/printは、flushしとかないと実行途中では出てこない。
  • 時間の加算は+じゃなくてtime+

2009年3月11日

Factorに入門する(5) parsing words

Factor入門第5回。 今回は"parsing words"について調べます。

通常、Factorのwordは、パーズされ解釈され、即スタックに影響を与えます。数値リテラルならスタックに積まれるし、wordなら実行されます。多くの場合、スペースで区切られたひとつのwordは、スタックのみに依存して動作します。

スタック系言語の、わたしに認識できる歳代の利点は、このように「文法構造」がほぼないので、文法部分にあたまを使わずに読み書きできる、ということです。文法構造を理解する必要もない。

でも一部に、その場でスタックとのやりとりをしない動作をするものがあります。たとえば、quotationのはじまりを示す"["。

( scratchpad ) [

このように、Factorの対話画面(listenerといいます、って入門第5回で紹介するのは遅すぎですね)で"["を入力して、リターンを押しても何も起きません。( scratch )のプロンプトすら出ません。

( scratchpad ) [
2 4 *

2 4 * と入力すると、普通は2がつまれ4がつまれ、そしてそれに乗算が適用されて、スタックに8がつまれますが、やはり何も起きません。

( scratchpad ) [
2 4 *
]

--- Data stack:
[ 2 4 * ]
( scratchpad ) 

"]" で閉じるとはじめてプロンプトが戻り、そしてquotation "[ 2 4 * ]"がスタックにつまれます。明らかに普通のwordとは動作が違います。

word "["は、Factorではふつうのwordではなく、"parsing word"として定義されています。Factorのドキュメントの解説を参照してみましょう。

The Factor parser follows a simple recursive-descent design. The parser reads successive tokens from the input; if the token identifies a number or an ordinary word, it is added to an accumulator vector. Otherwise if the token identifies a parsing word, the parsing word is executed immediately.

ふつうのwordでも、先にわたしが書いた「即スタックに影響を与えます」というのに対応するのは"added to an accumulator vector"だそうで、accumulator vectorというものに初遭遇です。さらに、parsing wordの場合は「即実行されます」と書かれています。即実行なのか。実例が出ているので試してみます。

( scratchpad ) : hello "hello world." print ; parsing  #! まず実例
( scratchpad ) hello
hello world.
( scratchpad ) : hello2 "hello world." print ; #! parsingじゃない版
( scratchpad ) hello2 #!結果同じじゃん
hello world.   
( scratchpad ) : hello3 "hello world." ; parsing #!スタックに文字列を残してみよう(parsing wordでは違反のはず)
( scratchpad ) hello3 #! なんじゃこりゃ

--- Data stack:
T{ decoder f ~input-port~ utf8 f }
104
101
108
108
111
32
119
111
114
108
100
46

parsing word, 気軽に始めたのですが、けっこう手強そうです。つづく。

2009年3月 6日

Factorに入門する(4) リテラル

順番むちゃくちゃFactor入門。予告も無視で今回はリテラルのいろいろ。これ調べていて気付いたこと: 前のエントリで書いたconventionsには出てこなかったですが、"foo:"は、parsing wordみたいですね。

数値

ふつうの整数、integer

1
-10
12345

分数、ratio。符号が分母・分子につくことあり。空白はあけない(Forthの子孫だし)

1/2
+2/5
-1/-2

ふつうに、2/5とかやってもratioが出てくる。

浮動小数点float。

1.25
-3.14
1.5e5

複素数complex。

C{ 1 2 }

word

wordのliteralは、\(バックスラッシュ)に続けてwordを書きます。

\ +

これだと、加算は実行されずに、word "+"がスタックに積まれます。そこでexecuteすると実行されます。この"\"はparsing word。スタックを消費するんじゃなくて、つづくソースコードをパーズするタイプのwordです。

quotation

quatationの表記もliteral。

[ 3 2 * ]

これ、対話形式で途中で改行いれてもいいんですよね。"["はparsing wordだからな

array

配列

{ 1 2 3 }

文字・文字列

文字リテラルはない。文字コードを扱うことはできる。CHAR: につづけての指定で文字コードをスタックにつめる。unicodeのコードポイントもかけます。

CHAR: x
CHAR: exclamation-mark

文字列リテラルはふつうにダブルクオートで囲む。stringオブジェクトは長さ固定。

"moji retsu"

sequences

Byte Array バイト列。ところでFactorには"protocol"という概念があるようで、これは"sequence protocol"を実装しています。そういえば文字列もsequenceです。

B{ 1 2 3 }

Vector。可変長sequenceだそうです。詳細はまだ理解していません。

V{ 1 2 3 }

String buffer。可変長の文字sequence。

SBUF" hello!"

SBUF"のあとにはスペースをあける必要あり。

Hashtable。ふつうの連想配列。

H{ { "name" "kojima" } { "web" "skoji.jp" } }

Tuple

Factorの名前つきslotを持っているオブジェクト。

T{ rgba { red 1.0 } { green 0.0 } { blue 0.5 } }

pathname

パス名。なぜstringと別に用意されているのかはまだ分かってません。

P" foobar.txt"

まとめ

超駆け足ですが、リテラルのいろいろでした。データ型としてよく分からないものもまだあります。parsing wordとかsequenceとかprotocolって概念も近々ちゃんと調べて書きます。

Factorに入門する(3) 名前づけの習慣

迷走するFactor入門生その3。本日は短いですが名前付のコンベンションについて。

参考資料はこちら、というか、ただ要約しただけです。すみません。

foo?
booleanを出力する。条件にあっているかテストする用ですね。
?foo
fooを場合によっては実行。
<foo>
fooのオブジェクトを新規作成。
>foo
スタックトップをfooに変換。>stringとか。
foo>bar
スタックトップのfooをbarに変換。
new-foo
スタックトップから引数をとって、何か新規オブジェクトを作成。
foo*
fooのaltanativeまたは、fooからよばれるジェネリックなword
(foo)
fooから呼ばれる実装詳細
set-foo
fooを新しい値に。set-lengthとか。
foo>>
スロットのゲット。(スロットってなんだ? オブジェクトの属性かな)
>>foo
スロットへのセット。
with-foo
新しい動的スコープの中で、fooに関わる初期化やクリーンアップをおこなう。
$foo
ドキュメンテーション用のマークアップ

次回は、実行時のスタック操作だけじゃなくて、パース時とかコンパイル時について調べるかもしれません。

Carbon Emacsから辞書.appを使う

以前は辞書引きアプリとしてJammingを使っていて、Emacsから辞書引きができるように設定していました(最初は日本語が通らなかったのですが、2ちゃんで質問やらやりとりやらやって、ちゃんとうごくようにしました。名無しで参加してましたがあれは私です。いまでも探せばアーカイブが出てきます:)。

さて、Leopardの辞書.app (Dictionary.app)は大変便利です。SafariみたいなCocoaアプリでは、単語を選択してCommand-Control-dで辞書が引けます。

これemacsからやりたいなー、と思っていたのですが、Dictionary.appのAPIがわからなくて(AppleScriptに対応してないみたいだし)、諦めていたのですが、方法がありましたよそれもとても簡単なのが。Tiger/Leopardでは、"dict://"というスキームでURLひらけば辞書が引けるのでした! 全く知らなかった。調査能力が低いです。というか、どこにそのドキュメントがあるのかも今の時点で分かりません。

というわけで、大変簡単ですがCarbon EmacsでDictionary.appを使うelisp書いてみました。jammingのときと同じキーバインドにしています。region 指定で辞書引くってのは全く使わないので今回は省略です。

;MacOS X Dict
(require 'thingatpt)
(defun macdict-lookup (word)
  "Lookup word with Dictionary.app"
  (call-process "open" nil 0 nil (concat "dict://" word)))
  
(defun macdict-lookup-word ()
  "Lookup the word at point with Dictionary.app."
  (interactive)
  (macdict-lookup (word-at-point)))

(global-set-key "\M-l" 'macdict-lookup-word)  

引きたい単語の上にポインタを置いて、M-lで 辞書.appが立ちあがります。

Cocoaアプリみたいなパネルで表示できるともっと嬉しいんだけど、あれはCocoaな親プロセスがいないと使えないのかな。

(追記 2009.3.6 15:00)
Carbon Emacsのmac-key-mode使えばコンテクストメニューで辞書引けるんですね...。しかもだいぶ前から実装されていました...。そのソースみれば、browse-urlで辞書引くってのが一目瞭然でした...。

2009年3月 4日

R言語: 統計モデル全然理解できね

お小遣い帳を分析しようとしたとしましょう。Rでxtabsを使うと、こんな風に、どの月にどのくらい何をつかっていたかが簡単に集計できてたいへん便利です(データは架空ですよ)。

> df <- read.csv("test.csv")
> df
   月度   品名   費目  費用
1     2 送別会   外食  4500
2     2  R入門   書籍  3000
3     2 飲み会   外食  8000
4     2   天ぷら   外食  9500
5     2   余市   酒手  1550
6     3   塊魂   娯楽   900
7     3 ビール   酒手  5880
8     4 ビール   酒手  5880
9     4 ワイン   酒手  2100
10    4   定期 交通費 12000
> xtabs(費用 ~ 費目 + 月度, df)
        月度
費目       2     3     4
  外食   22000     0     0
  娯楽       0   900     0
  書籍    3000     0     0
  酒手    1550  5880  7980
  交通費     0     0 12000
>

...って意味わかんね! xtabsの第一引数は、「統計モデル」だそうで、~の左が目的変数・右が説明変数、かんぜんにちんぷんかんぷんです。勉強したおぼえもない。統計学はたいへん苦手な科目だったんですが、分かると世界がひろがりそうだから、勉強しなおそうかなあ...

Factorに入門する(2) Quotation

道しるべがないままのFactor入門第二回。

今回は、ForthにはなかったQuotationについて。まずは実例から。

( scratchpad ) 2

--- Data stack:
2
( scratchpad ) [ 3 * ] ! これがQuotation

--- Data stack:
2
[ 3 * ]
( scratchpad ) call . ! [ 3 * ] が評価・実行される
6
( scratchpad ) 

[]で囲った中身は、すぐには評価されないカタマリになるようです。それがquatation。ドキュメントでQuatationをひいてみると、こんなことかいてあります。

Conceptually, a quotation is an anonymous function (a value denoting a snippet of code) whichcan be passed around and called.

Concretely, a quotation is an immutable sequence of objects, some of which may be words, together with a block of machine code which may be executed to achieve the effect of evaluating the quotation. The machine code is generated by a fast non-optimizing quotation compiler which is always running and is transparent to the developer.

概念としては無名関数。具体的には、オブジェクトのシーケンス、だそうです。無名関数ぽい使い方といえば、mapとかeachですかね。

( scratchpad ) : concat ( array -- seq ) "" swap [ append ] each ;
( scratchpad ) { "dobin" "chobin" "hagechobin" } concat . 
"dobinchobinhagechobin"
( scratchpad ) { "dobin" "chobin" "hagechobin" } [ reverse ] map .
{ "nibod" "nibohc" "nibohcegah" }
( scratchpad ) : palindrome? dup reverse = ; 
( scratchpad ) { "dobin" "chobin" "tattarrattat" "hagechobin" } [ palindrome? ] map .
{ f f t f }

Factorでは、if文などの制御構造でもこのquatationをつかいます。

( scratchpad ) : positiveYN ( n -- ) 0 > [ "Yes" ] [ "No" ] if print ;
( scratchpad ) 3 positiveYN
Yes
( scratchpad ) -1 PositiveYN
No

んー、Forthのifよりは、一貫性がある感じかな。ちょっと読みづらいけど。

2009年3月 3日

R言語入門: Rはベクトル操作がすごい

Rの基礎とプログラミング技法『Rの基礎とプログラミング技法』を読みながら、R言語の勉強中です。遠い昔にS-PLUSを使えたこともあったので、「再」入門かな。

この本はコンパクトにまとまっていて、なかなかよい本です。Rに関する多くの本は「統計解析」に重きがおかれていますが、この本は「言語の説明」に重点があります。

今回は基礎の習得の部分から「ベクトル操作がすごい」ことについて書きます。

Rの基本的なデータ型は「ベクトル」です。そしてベクトル同士の演算処理がいろいろ用意されています。

たとえば、"apple", "pear", "orange"のそれぞれが、3,2,1個あるとき、こんな表を作ります。excelでつくってcsvではいてもいいですね。

test.txt

product,amount
apple,3
pear,2
orange,1

で、これを読み込みます。そして、apple/pear/orangeをそれぞれ、その個数繰り返したベクタを作ります。

> l <- read.table("/Users/skoji/test.txt", sep=",", header=TRUE) # 読み込みます
> l
  product amount
1   apple      3
2    pear      2
3  orange      1
> rep(l$product, l$amount) # ベクタproductの要素を、それぞれamount回くりかえします
[1] apple  apple  apple  pear   pear   orange
Levels: apple orange pear

この、repでの指定の仕方がRですね。ベクタにたいして、ベクタで指定した回数だけ何かをする、ってパターンがよくあります。定型的なデータ処理ならループ構文いらず。

さっき読み込んだ表にたいしても、いろんなことができます。この例だと単純すぎるけど、データベース的なことできるんですよね。

> subset(l, product %in% c("apple","pear")) # productがappleまたはpearであるもの
  product amount
1   apple      3
2    pear      2
> subset(l, amount > 2) # amountが2より大きいもの
  product amount
1   apple      3

このデータ型は「データフレーム」というそうです(この本読むまで知らなかった)。

単純な一次元ベクトルについても、添え字でいろいろな操作ができます。できすぎです。

> x <- c(5,3,1,-1,9,100,10)
> x[3] # 3番目の要素
[1] 1
> x[c(5,1)] # 5番目と1番目の要素を、その順番で
[1] 9 5
> x[-c(5,1)] # 5番目と1番目の要素を除いたもの
[1]   3   1  -1 100  10
> x[c(TRUE,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE)] # TRUEのところだけ
[1] 5 9
> x[x < 4] # 4未満のものだけ
[1]  3  1 -1
> x[1:3] <- c(4,3,2) # 1,2,3番目の要素を4,3,2で置き換える
> x
[1]   4   3   2  -1   9 100  10
> x[x>8] <- 0 # 8より大きい要素は0にする
> x
[1]  4  3  2 -1  0  0  0
> 

2009年3月 2日

Factorに入門する(1) とにかく使ってみる

Forthの流れをくむ言語はいろいろありますが、今いちばん熱そうなFactorをつまみぐいしてみています。

環境設定

インストールはとても簡単です。Macでは(おそらく他のプラットフォームでも)ダウンロードして適当な場所に置くだけ。

そのままでも、GUIなWorkspaceが使えますが、わたしはemacsで使います。emacsの設定は、factor/misc/fuel/READMEに従って実施。

基本概念

word
関数・命令のこと。Forthと同じ。
Vocaburary
パッケージのようなもの。名前空間を分離した、wordのあつまり。

チュートリアル

オンラインのドキュメント(配布物にも同じ内容が同梱されてる)に、Your first programってのがあるので、まずはこれにしたがってやってみましょう。

vocaburary作成

この指示に従い、まずはオレ用vocaburaryを作成。Emacsなので、M-x fuel-scaffold-vocabを使ってみました。

で、超簡単なword (palindrome?)を定義したら、このtutorialでは"Press F2"ってかいてある所、C-c rでfuel listnerに戻ると、vocaburaryを読み直してくれます。

emacs上でhelpを引くのは、C-c h。

このチュートリアルは、回文を判定するwordを作るだけです。かなり短くて、あっという間におわります。印象的だったこと:

  • vocaburaryのテンプレートを作成するためライブラリが標準で存在する
  • テストのフレームワークも標準で含まれている。書き方も実行もとても簡単。
  • ドキュメンテーションもどうやらFactorのコードで書くようです。
  • ワード定義に書くカッコで囲まれた部分。Forthでは習慣として実行前・実行後のスタック状態を書く単なるコメントでしたが、Factorでは機能が割り当てられた構文(Stack effect declaration)だそうな。

stck effect declaration

Forthではただのコメントだったものがどう進化したかチェックしてみました。inferまたはinfer.というwordでチェックできるみたいです。

( scratchpad ) : legal-func ( x y z -- x ) * + ; ! 正しいstack effect declaration
( scratchpad ) 1 2 3 legal-func .
7
( scratchpad ) [ legal-func ] infer.  ! チェック
( object object object -- object )
( scratchpad ) : illegal-func ( x -- x ) dup 1 + ; ! 正しくないdeclaration。ただしくは( x -- x y )
( scratchpad ) 1 illegal-func . 
2

--- Data stack:
1
( scratchpad ) .
1
( scratchpad ) [ illegal-func ] infer.
 In word: illegal-func
Stack effects of the word illegal-func do not match.
Inferred: (( object -- object object ))
Declared: (( x -- x ))

Type :help for debugging help.
( scratchpad ) : illegal-or-legal ( str -- str ) length ; ! 数はあってるけど正しくは ( str -- n ) 
( scratchpad ) "foobar" illegal-or-legal .
6
( scratchpad ) [ illegal-or-legal ] infer. ! 数しかチェックしてないのでOK。
( object -- object )
( scratchpad ) 

この後調べたいことメモ

リテラルのいろいろ・実行モデル詳細(データスタック以外のスタックとか、辞書とか)ソースをパースするタイプの命令のモデル(USE: とか \とか)・スレッドでのスタック扱い(継続ベースの軽量スレッドがあるみたい)・Combinatorとはなんぞや・等々