Programmer's Note

コード読み書きの備忘録。

sicpの導入部

MITのプログラミングの授業で使われていた伝説的な教科書、「Structure and Interpretation of Computer Programs」、略してsicpを読み始めた。
いわゆるプログラミングの古典的名著として数えられ、「ハッカーと画家」のポール・グレアムAmazonレビューで絶賛している。(というかLISPerにとってはバイブルなのかしら。)
内容的に課題として小難しい数学の問題を解いたりとあるみたいで、どこまで続くか分からんが、楽しく読んでいきたい。
というか、導入文はもうえらく名文である。実にわくわくする。
Wizard本*1と呼ばれているらしいが、この冒頭ではComputer Programを魔法のスペルに喩えているのだ。

    A computational process, in a correctly working computer, execute programs precisely and accurately. Thus like the sorcerer's apprentice, novice programmer must learn to understand and to anticipate the consequence of thier conjuring.
    Fortunately, learning to program is considerably less dangerous than learning sorcery, because the spirits we deal with are conveniently contained in a secure way.


教科書でこのユーモアかつ想像力に富んだ導入は日本では考えられない。
古くは数学、科学が占星術錬金術と同等に列していた西欧の感覚が織り込まれていて、なんともロマンを感じる。

*1:本書の表紙が魔法使いの師匠と弟子の絵になっているのもWizard本と言われるゆえんだろう

vimrcメモ

vimrcメモ。 プラグインも色々入れていたが、使用頻度が低いので思い切って削って、とりあえず必要最小限のものだけを残してみた。 運用していくうちにまた増えたりするかもしれんが。

だいたいがネットで検索した設定をコピペして、ミックスした感じだが。

set nocompatible

" Enable file type detection and do language-dependent indenting.
filetype plugin indent on

" Switch syntax highlighting on
syntax on

" Show line numbers
set number

" C indent setting
set cindent
set cinoptions+=:0 "Change indent rule of 'case' statement

" Tab width, no expand to space
set tabstop=4 shiftwidth=4 noexpandtab

" Highlight search word, increamental hightlight
set hlsearch
set incsearch

" Command Make will call make and then cwindow which
" open a 3 line error window if any errors are found.
" if no errors, it closes any open cwindow.
:command -nargs=* Make make <args> | cwindow  3
:map <Leader>j :Make<CR>

autocmd QuickFixCmdPost [^l]* nested cwindow
autocmd QuickFixCmdPost    l* nested lwindow

" for GLOBAL indexing
map <C-g> :Gtags
map <C-h> :Gtags -f %<CR>
map <C-f> :GtagsCursor<CR>
map <C-j> :cn<CR>
map <C-k> :cp<CR>

yacc を遊ぶ:パーサーの動き確認

「THE UNIX PROGRAMMING ENVIRONMENT」のチャプター8のhocをサンプルに、yaccのパースの動きを確かめてみる。

この本では、hoc4でパーサーからインタプリタコードを生成するステップに移るが、 生成すべきコードとの結びつきがイマイチ想像できんかったから。

とりあえず、サンプル:

[hoc.y]

%{
#include <stdio.h>
#include <ctype.h>
#define YYSTYPE double
%}
%token NUMBER
%right  '='
%left   '+' '-' /* left associative, name precedence */
%left   '*' '/' /* left assoc., higher procedence */
%%
list:   /*nothing*/
        | list '\n'         { printf("list\n"); }
        | list expr '\n'    { printf("list expr: %f\n", $2); }
        ;

expr:   NUMBER              { printf("NUMBER: %f\n", $1); $$ = $1; }
        | expr '+' expr     { printf("%f + %f\n", $1, $3); $$ = $1 + $3; }
        | expr '*' expr     { printf("%f * %f\n", $1, $3); $$ = $1 * $3; }
        | '(' expr ')'      { printf("( %f )\n", $2); $$ = $2; }
        ;
%%
int main(int arc, char **argv) {
    yyparse();
}
int yyerror(char *s) {
    fprintf(stderr, "%s\n", s);
}
int yylex() {
    int c;

    while ((c=getchar()) == ' ' || c == '\t') {
        ;
    }
    if (c==EOF) {
        return 0;
    }
    if (c=='.' || isdigit(c)) { /*NUMBER*/
        ungetc(c, stdin);
        scanf("%lf", &yylval);
        return NUMBER;
    }
    return c;
}

[Makefile]

TARGET = hoc
OBJS = y.tab.o

all: $(TARGET)

$(TARGET): $(OBJS)
    gcc $(OBJS) -o $@

y.tab.o: y.tab.c
    gcc -c $< -o $@

y.tab.c: hoc.y
    yacc $<

clean:
    rm -f y.tab.c
    rm -f $(OBJS)
    rm -f $(TARGET)

さて、実行してみる。

hoc4_test $./hoc
1+2+3
NUMBER: 1.000000
NUMBER: 2.000000
1.000000 + 2.000000
NUMBER: 3.000000
3.000000 + 3.000000
list expr: 6.000000

なるほど、これ分かりやすい。 仮想スタックマシンの命令はPUSHPOP、 と演算命令なので以下のような感じかな。

NUMBER: 1.000000     :  -> PUSH (NUMBER)
NUMBER: 2.000000     :  -> PUSH (NUMBER)
1.000000 + 2.000000  :  -> res = ADD (POP() + POP()); PUSH (res);
NUMBER: 3.000000     :  -> PUSH (NUMBER)
3.000000 + 3.000000  :  -> res = ADD (POP() + POP()); PUSH (res);
list expr: 6.000000  :  -> 結果 = POP()

まあ、演算命令ADDはスタックから値を取り出すところも 命令の中に含まれるだろうが。

「The UNIX Programming Environment」読了

「The UNIX Programming Environment」読了。1月からコツコツ読んで足がけ4ヶ月。正確には第9章を残しているが、第9章はtroffの紹介で、これはまあ気が向いたら読めばよいかなと思っている。

文章整形は1980年代からはもはや隔世の感がありすぎる。恐らく今後troffは使うことはないだろうし。

逆に言えば、1章から8章まで今でも通用する内容だったということの方が凄いかもしれない。

ほんとにプログラマの作業場としてのUNIXの基礎はこの本が書かれた時代と変わらない。実にたくさんのことを学ぶことができた。

個々ツールの細かいTIPSもあるが、一冊を読み通すことでUNIXカルチャーの薫陶を受けることができたかなと思う。

KernighanとPikeが自分のチューターとして懇切丁寧にイロハを教えてくれた感じ。そういう疑似体験ができたことが何よりで、本を一冊読んだだけで成長を実感できるってそうそうないと思う。

というのも、この本はそういう風に書かれている、というのが大きい。Kernighan先生の本はどれも実用的で面白い例をベースに語っている。読み終えた頃に確実にレベルアップしている。

さて、UNIXの考え方の醍醐味は、シンプルで小さなプログラムを組み合わせれば、複雑な問題をも解決できること。
完全な解決を求める必要はないこと(問題が8割、9割解決できればいい)。
完璧なものを最初から作ろうとするのではなく、作りながら改善していくこと。
さらには自分で一から何でも作ろうとしない、すでにあるツールをまず活用できないか考えること。
など、とことん実用主義な点にあるかなと思う。
ここには、アイディアがあったらまずは試してみる、という精神に溢れている。

UNIXはそういことをやるにはベストな環境。普段使ってる環境の本質を理解してこれから使っていける。という意味でやっと入門できたかなと。


ハッカーと画家: 言語の力

ちょっと衝撃を受けた。 昨日読み始めたポール・グレアムの「ハッカーと画家」、これはすごい本だ。

結構前に、Matzさんの以下の記事で知ったのだが、

まつもとゆきひろのハッカーズライフ:第3回 ハッカーと仕事 (2/2) - ITmedia エンタープライズ

ずっとブックリストに入れたままだった・・・これも早めに読んでおくべきだった。 実に色々示唆に富む内容で考えさせられる。良い本は刺激をくれ思考させてくれる本だ。

とりわけ衝撃的だったのは、「言語の力」をとうとうと説いてる章の以下の一文。

あたなが難しい問題を解こうとしているなら、問われているのはパワフルな言語を使うか使わないか、ではない。 (a)パワフルな言語を使うか、(b)パワフルな言語と等価なインタプルタを書くか、(c)自らがパワフルな言語の人間コンパイラとなるか、という選択なのだ

...

コンパイラがやるべきことを人間がシミュレートするという慣行はただ広まっているというだけでなく、思考を型にはめる作用がある。 例えば、オブジェクト指向の世界ではよく「パターン」というのを耳にするだろう。この「パターン」は多くの場合、(c)のケース、すなわち人間コンパイラが動作してる証拠なんじゃないかと私は思う。

こりゃ、こういう視点なかったな。 言語レベルでパラダイムが変われば、パターンとかフレームワークとかは、実はそもそもいらない。 このものの見方があるかないかでずいぶん違うな。

Joel on Software読み始める

最近 Joel on Software を読み始めた。

以前、書店でぱらぱら見たときは面白そうに見えなかったが、Kindleで原書のお試し版を読んでみると、楽しいではないか。とても平易な英語で読みやすい。

ということで、原書のペーパーバック古本をAmazonで購入。すこし汚れていたが、まあ印刷がクリアであれば全然問題ない。

そして、読んでて楽しい。 著者は言いたいこと言ってる感じで、ユーモアに富んでるし、主張してることも納得できる。

これ、もうちょっと早くに読んでおけば良かったな、と。とはいえ、英語読書に慣れてきたのは最近だから、この本が出た2004年は絶対読んでなかったな。

まあ、教訓は翻訳本の内容は原書を読んでから判断すること、だ。技術書に限らず、すべてのジャンルに言えることだけど、日本人作家でも好きな作家とそうでない作家がいる訳で、訳本はやっぱ翻訳者の作品だなと痛感。

さて、まだ1/3程度だが、読んで思ったのはこの人は経験に裏打ちされた現実主義者だな。と。 だいたいにおいて、プロジェクトマネージャーは夢見がちな人種が多いけど、この人は技術者寄りの視点を持っている。(というか技術者だろうけど)

現場で界王拳を多用しても、しょせん現実は20%くらいパワーアップしない。なのに、しっぺ返しは絶対にくらう、的なことを言っている。

仕様書を書く上で重要なことはFunnyであること、と言っているのはぐっと来た。 ユースケースを多少ふざけて書くという発想なかったな。これは確かに楽しい。

結局、仕様書は書かなきゃいけない。そこはさぼれない。 (つまり、仕様書を書かないデメリットを打ち消すウルトラCはない) ならば楽しく書こうではないか。という発想だね。

awk / yacc / lex

いかん、忙しさにかまけて更新が滞っている・・・。 さて、コンスタントに読んでいる「The UNIX Programming Environment」は、第6、7章が終わり。8章に入っている。 yaccで簡易計算言語の作成だぜ。さすがはKernighanさんとPikeさん、yaccがこんな風に楽しいものとは。 すべてはつながっているというか、yaccというツールは、awkと発想が似ている。

list:
        | list '\n'
        | list expr '\n'    { printf("\t%.8g\n", $2); }
        ;
expr:   NUMBER              { $$ = $1; }
        | expr '+' expr { $$ = $1 + $3; }
        | expr '-' expr { $$ = $1 - $3; }
        | expr '*' expr { $$ = $1 * $3; }
        | expr '/' expr { $$ = $1 / $3; }
        | '(' expr ')'      { $$ = $2; }
        ;

つまり、 左側にパターンを書いて、右側にそのパターンが適合した時の処理を書く、 という点において。$1, $2の発想もね。

lexにいたっては、左側に正規表現を書いて右は処理を書く、からほとんどawkと一緒だ。

このパターン認識側の言語って、どれがオリジンかは分からんが、 shell, ed, sed, awk, yacc, lex。 これらぜんぶ初期UNIXの文化の中から生まれた、と考えたら似てて当たり前かもしれない。 が、面白い。