UL20Aデスクトップ

Windows7

Windows7は、デフォルトでこういったアートワークテーマがあるのがいい。一定時間ごとにと背景が別の絵に切り替わっていきます。画面は1366x768だけど、そこそこ広く使えてます。

Ubuntu 9.10 on VirtualBox

ホスト→ゲストへのクリップボードはコピーされます(逆はできていない)。chromium-browserを入れてます。

sudo add-apt-repository ppa:chromium-daily

を数回やるとapt lineに追加されます。

おまけ: CPU-Z

BIOSでのオーバクロック5%設定ですが、利いてるようです。

UL20A Windows7セットアップ

ASUS UL20A届いた - ラシウラのUL20Aを整備しました。UL20Aは、ふたを閉じるとハイバネーションで、電源ボタンがサスペンドになっていたりとというような、なかなか愉快なデフォルト設定で、そのあたりから直していきました(Express Gateを使うためには、サスペンドじゃいけないからだろうけど)。

入れたパッケージ

初のWindows7機だけど、あまりVistaと変わらなくて拍子抜けかも。最近は、昔ほどソフトを入れることもなくなってきたなと感じました。(サブノートなので、VisualStudio環境や動画編集環境は今回はパスしてます)。

ひとつ残念なのはVirtualBox 3.0.12上のゲストubuntu karmic amd64が異様に重くなってしまう点。Intel VT-xが原因、みたいな報告もありますが、linuxamd64で使うにはそれをoffにすることもできないようなので、32bit版ubuntuを入れました。(もしかしてハード側のBIOS設定が必要なのかも)。

設定

KeySwapで「CAPS Lock」キーには「右Ctrl」を割り振ったほかには、regeditを使ってX-Mouse化してます。

  • "HKEY_CURRENT_USER\Control Panel\Desktop"の
    • "UserPreferencesMask"編集: 最初の数値を0x41足し上げる(元が0x9eなら0xdfになる)
    • "ActiveWndTrkTimeout"作成: DWORD値でつくり、10進で500にする(0x000001f4)
      • (既存のActiveWndTrackTimeoutではないので注意)

タスクバーは右置きにしました。デフォルトでは出ていないquick launchを表示させています。

  • 右クリックメニュー「ツールバー」-「新規ツールバー(N)」で出るファイルダイアログの「フォルダー」欄に"shell:quick launch"といれ、「フォルダーの選択」ボタンを押せばクイックランチが出てくる。

IME設定はいつものように、キー設定で、「無変換」に「IME OFF」、「変換」に「IME ON」となるよう割り当てる。オートコレクトはASCIIがある文字は半角になるように設定しました。

Windows7でのIE無効化

コントロールパネルで「プログラムと機能」を開き、左にある「Windowsの機能の有効化または無効化」を押すとダイアログが出るので、その一番上にある「Internet Explorer 8」のチェックをはずして「OK」ボタンを押し、再起動したらIEが無効化されます。

ASUS UL20A届いた

ASUS 12.1型ワイドノートPC UL20A Windows7搭載モデル シルバー UL20A-2X044V

ASUS 12.1型ワイドノートPC UL20A Windows7搭載モデル シルバー UL20A-2X044V

BUFFALO ノートPC用増設メモリ PC2-6400 (DDR2-800) 2GB D2/N800-2G/E

BUFFALO ノートPC用増設メモリ PC2-6400 (DDR2-800) 2GB D2/N800-2G/E

をつけてamazonで57700円、二日前の夜に注文したときは配達まで1-3週間だったけど、今日届きました。

本体は、Aspire 1410とくらべると若干重く、大きいかんじがします。増設メモリは、裏面にあるふたを+ネジ精密ドライバーで3つはずしたら、メモリスロットが二つあって、手前側の空きスロットのほうに指せばOKでした。

以下、初期状態での感想を列挙しておきます

プラスポイント

  • 価格
  • 64bit windows7
  • ASUS Live Update
  • 余計なアプリが入ってない
  • 右にもFnキー
  • ACアダプタが小さめ
  • 蓋にかみ合わせロックが無い
  • オーバークロック(0-5%)?
  • 本体が熱くならない

マイナスポイント

  • タッチパッドのボタン(左右一体型で押しが重い)
  • いい加減なステッカー張り(とくにWindows7ステッカー)
  • Express Gate(便利だが、解像度があってない。解像度変更できない)
  • スピーカーが下付け(音質はよい。ただ、寝ながらは不利)
  • ウィルスバスター試用版(いらね)
  • Dドライブ分割(分割するにしてもC80:D200は大きすぎでは。Cに統合した)
  • グレアパネル(それほどまぶしいというわけでもないけど)

エクスペリエンスインデックス

ITMediaのUL20Aレビュー記事とくらべるとプロセッサ以外は上になってる。差はメモリが4GBなのと、オーバークロック5%(初期状態は3%だった)にしたくらいだろうけど。メモリがでかいのかな。

go言語snippetと注意点

以前書いたpythonicなA*関数をままgoで書いてみました。

そのとき調査で理解したものを紹介します。

0値

goの0値(初期値を設定しないときのデフォルト値)がどうなるか、そしてどう比較するかの例です。

package main

import "fmt"

type location struct {
        x, y int
}

func main() {
        var v location;
        fmt.Printf("%v\n", v);
        //fmt.Printf("%v\n", v == location{}); // not allowed
        fmt.Printf("%v\n", v.x == 0 && v.y == 0);

        var a *location;
        fmt.Printf("%v\n", a == nil);
        var b []location;
        fmt.Printf("%v\n", b);
        fmt.Printf("%v\n", b == nil);
        var c string;
        fmt.Printf("%v\n", c);
        fmt.Printf("%v\n", c == "");
        var d map[string]float;
        fmt.Printf("%v\n", d);
        fmt.Printf("%v\n", d == nil);
}

大体予想通りです。ただ、struct同士は==で結べません。各メンバーが0値かどうかを比較することになるでしょうか。

nilのメソッド呼び出し

structのポインタはnilでもメソッドが呼び出せます。

package main

import "fmt"

type foo struct {
        val int;
}
func (obj *foo) IsNil() bool {
        return obj == nil;
}
type nilable interface {
        IsNil() bool;
}

func main() {
        var o *foo;
        fmt.Printf("%v\n", o.IsNil());
        //var i nilable;
        //fmt.Printf("%v\n", i.IsNil());
}

interfaceがnilの場合、メソッドが解決できずエラーが起きて死にます(コレは正しい動きなのでしょうか?0値返すべきじゃないか、とも思うけど)。

for rangeループ

rangeループで何が返るかを調べました。

package main

import "fmt"

func main() {
        s := "abcdef";
        for _, c := range s {
                fmt.Printf("%f\n", c);
                fmt.Printf("%f\n", c == 'd');
        }

        a := [...]string {
                "abc",
                "def",
                "ghi",
        };
        for _, l := range a {
                fmt.Printf("%f\n", l);
                fmt.Printf("%f\n", l == "ghi");
        }

        m := map[string]int {
                "abc": 10,
                "def": 20,
                "ghi": 30,
        };
        for k, v := range m {
                fmt.Printf("%f\n", k);
                fmt.Printf("%f\n", v);
                fmt.Printf("%f\n", v == 20);
        }

        g := func(size int) <-chan int {
                ch := make(chan int);
                go func () {
                        for i := 0; i < size; i++ {
                                ch <- i * 2;
                                ch <- i * 2 + 1;
                        }
                        close(ch);
                }();
                return ch;
        };
        for v := range g(3) {
                fmt.Printf("%f\n", v);
        }

}
  • 文字列と配列は、インデックスと要素
  • マップは、キーと値
  • channelは、値のみ

最後のはpythonのgenerator風にgoroutineを使っています。

def g(size):
    for i in range(size):
        yield i * 2
        yield i * 2 + 1

for v in g(3):
    println(v)

channelの型

  • "chan T"がchannelの型です。makeで使うし、送受信可能です。
  • "<-chan T"は受信専用のchannel型です。
    • イテレータ的にchannelを用いる場合、この型を返すといいでしょう。
  • "chan<- T"は送信専用のchannel型です。
ch := make(chan T); // type(ch) == chan T
var receiver <-chan T = ch;
var sender chan<- T = ch;

普通は送信か受信専用として受け渡ししてもらうのがわかりやすいでしょう。

vectorの使い方

package main

import "fmt"
import "container/vector"

type ilocation interface {
        String() string;
}
type location [2]int
func (loc *location) String() string {
        return fmt.Sprintf("%v", *loc);
}

func main() {
        v1 := vector.New(0); // v := vector.New(len) => v.Len() == len
        v1.Push(&location{5, 20});
        v1.Push(&location{50, 10});


        fmt.Printf("%v\n", v1);
        v1.Do(func (elem vector.Element) {
                fmt.Printf("%v\n", elem);
        });
        v1.Do(func (elem vector.Element) {
                fmt.Printf("%v\n", elem.(ilocation).String());
        });
        for _, elem := range v1.Data() {
                fmt.Printf("%v\n", elem.(*location).String());
        }
        for _, elem := range v1.Data() {
                fmt.Printf("%v\n", elem.(ilocation).String());
        }
        // ptr array cast not allowed?
        //for _, elem := range v1.Data().([]ilocation) {
        //      fmt.Printf("%v\n", elem.String());
        //}

        v2 := v1.Slice(0, v1.Len()); // copy
        v2.Set(0, &location{0, 0});
        fmt.Printf("%v\n", v1);
        fmt.Printf("%v\n", v2);
}

型変換

intからfloat64へなどの型変換は、以下のように行います。多くの場合、暗黙に変換されません。

a := 10; // int
b := float64(a); // float64 

heapパッケージ

pythonのheapqのようなことができるheapパッケージがあります。
ただし、キュー本体になるために必要なheap.Interfaceのメソッド群は、Vectorがほぼ同じものを持っているのですが、型などに微妙に違いがあるため、インタフェースをすりあわせる必要があり、使い方は若干複雑です。

import "fmt"
import "container/vector"
import "container/heap"

type scored struct {
        score float;
        data string;
}

type heapq struct {
        vector.Vector;
}
func (queue *heapq) Init(len int) *heapq {
        queue.Vector.Init(0);
        return queue;
}
func (queue *heapq) At(i int) *scored {
        return queue.Vector.At(i).(*scored);
}
func (queue *heapq) Less(i, j int) bool {
        return queue.At(i).score < queue.At(j).score;
}
func (queue *heapq) Push(o interface {}) {
        queue.Vector.Push(o.(vector.Element));
}
func (queue *heapq) Pop() interface {} {
        return queue.Vector.Pop();
}

func main() {
        queue := new(heapq).Init(0);
        println("ok0");
        heap.Init(queue);
        println("ok1");
        heap.Push(queue, &scored{10.0, "go"});
        println("ok2");
        heap.Push(queue, &scored{5.0, "java"});
        heap.Push(queue, &scored{7.0, "python"});
        heap.Push(queue, &scored{1.0, "c++"});
        heap.Push(queue, &scored{3.0, "c"});

        println("ok3");
        for queue.Len() > 0 {
                data := heap.Pop(queue).(*scored);
                fmt.Printf("%v\n", data);
        }
        println("ok4");
}

Vectorの要素が、vector.Elementじゃなく、interface{}だったらPush/Popの上書きいらないのに。

newとComposite literal

type Foo struct { .... }

という型について、二つのインスタンス生成式

&Foo{}

new(Foo)

はまったく同じものです。前者がスタック上に詰まれるとか、ループ中でメモリ領域が再利用されるとか、そういうことはありません

前者のリテラル形式(から参照を得る記法)では、初期データを入れられたりして便利です。しかし、このリテラル形式では生成できない型があります。たとえばポインタ型とか。そういう場合にはnewしか手段がありません。

課題

pythonとgoとでのA*探索を書いてくらべてみると、増えてる部分の多くが組み込みTupleが無いことに由来する感じがします。
tuple的ペアを作成し、vectorの大小比較を再実装したりします。これは、pythonのtupleでは自然に備わってる機能、同値判定、大小判定、mapキー利用可能性が無いからだと思います。


ほかの差では、

  • comprehensionがなく、メモリ確保後にループしなくてはいけないこと
  • べき乗演算子が無くmath.Powやmath.Sqrtをつかわなくてはいけないこと
  • リテラルはfloatだけど、mathの関数の引数や結果でつかわれてるのはfloat64であること
  • オペレータオーバーロードがないため、スコアを抽象化しようとすると、逆に単純な数値が使いにくくなること
  • interfaceに多相型ができないため、コールバックでtype assertion(ダイナミックキャスト)を多用しなくてはいけないこと

などが気になったところです。そういう点を除いてもC、Javaに比べればだいぶコンパクトに書けると思いました。

増えてる多くはtuple代わりに用意した型に関係するものなので、goに慣れればもう少し書く量を減らせるかもしれません(interfaceにジェネリクスが実装されれば、tupleライブラリができるんだろうけど...)。

Goをちょっと使ってみた

いきなり大人気のgoをすこし触る。Rob PikeやKen Thompsonとかが作っているというだけですごいと思ってしまいます。

ビルド

ubuntuの場合、 http://golang.org/doc/install.html に書いてあるとおりすればコンパイラやリンカなどのツールのバイナリができあがります。

コンパイラやリンカはアーキテクチャごとに名前が違い、

  • 386用: 8g, 8l
  • amd64用: 6g, 6l
  • arm用: 5g, 5l

のようです(FAQによると、Plan9の伝統らしい)。

また、環境変数GOROOT,GOOS,GOARCHは、コンパイラやリンカの実行時にも必要なものです(生成バイナリの実行には不要)。.bashrcにかいとくとか、sourceコマンドなどで簡単に取り込めるようにしとくといいでしょう。

emacsモード

ソース中のmiscにemacsvimMacXcodeのためのgoモードが入ってます。

emacsの場合、go-mode-load.elとgo-mode.elがあります。このふたつのファイルを~/.emacs.d/の直下にコピーし、~/.emacs.elに

; ~/.emacs.d/に野良モードなどを置けるようにする設定。
(setq load-path (cons (expand-file-name "~/.emacs.d/") load-path))

(require 'go-mode-load) ; 実質go-modeのために書くのはこれだけ

とかけば拡張子が".go"なファイルを開けば、goモードになります。

例プログラム: exp/evalで文実行

最初のほうに書くプログラムというのは、その人の特徴がでてるかもしれません。自分の場合、evalがあるかどうかを調べています(つまり最初はアプリにしない)。

// 8g doeval.go
// 8l -o doeval doeval.8
package main

import "exp/eval"

func main() {
        world := eval.NewWorld();
        code, err := world.Compile(`
                print("Hello\n");
        `); // does not supoort package

        if err != nil {
                panic(err.String(), "\n");
        } else {
                if value, err := code.Run(); err != nil {
                        panicln(err.String());
                } else println(value);
        }
}

以下、注目した特徴

コーディングスタイル

まず、goのコーディングスタイルでのインデントはハードタブのようです。ソース付属のテストコードもそうだし、その設定はきっちりツールgofmtのデフォルトやemacsモードファイルでもなされています。

exp/evalパッケージ

exp/evalには簡単な文インタプリタが実装されています。この機能ではinterfaceやpackage/importの解釈は実装されていません。

パッケージ名

パッケージ名は単一識別子のみで、使う側がimport時に名前を変えて割り当てることで、使い分ける仕組みのようです。たとえば以下のようなかんじでしょうか:

import fooDom "foo/dom"
import barDom "bar/dom"

また、main.mainという関数が、コマンド実行で起動される関数になっています。

変数宣言の簡略形式

変数宣言は複数の形式があります。

Cのように同名の変数をかぶせて宣言できるようです。

複合文のセミコロン省略

文を区切るセミコロンはいくつかの場面で省略可能です。
rubyなどとちがい、"}"と宣言での")"のだけととても限られています。

つまり、例コードだとpanic、panicln, printlnのあとのセミコロンは省略可能です。

文字列リテラル

バッククオートでくくる文字列リテラルは、改行やハードタブも含めそのままの内容が文字列になります。

if文

if文はオプションで条件の前に代入文などの単純文を一つ埋め込めます。

もう一つ変わってるのは、if文の真部はblock文にしなくてはいけないが、偽部は任意の文が使えるというところもでしょうか。

条件式

条件式は"bool"値("true"/"false")のみつかえます。そのため(ポインタ型やスライス型の)変数に値があるかどうかの判定では、"nil"と比較することになります。

組み込み関数

"print"や"panic"は組み込みの関数です。

ずっと残るかどうかは保証しないようですが。

その他仕様で注目した点

"++"/"--"や代入が式ではなく文になっている

そのかわりifやswitchでオプションで文を一つ書けるようにしたという感じでしょうか。

リフレクションなどがあるunsafeパッケージ
interface型

型システム上は、メソッドセットの包含関係でチェックする。

興味深いのはstructに埋め込むことができる点で、そのまま同interfaceをもつことになるようだ(structどうしでもinterfaceどうしでもできるけど)。

あと細かい点だと、レシーバはポインタですが、interfaceの場合、structポインタと違いnil値に対してもメソッドが呼べないでした。

パッケージのinit関数

こういった機能は最近の言語では普通だけど。

設計判断の多くはFAQにもあるので必見です。

python用vim設定

"vim python"などで検索すると、vim用のpython設定らしきものがいろいろとあるが、smartindentやcinwordsをハック的に使うものが多く、ここ最近のものですら"filetype indent on"を使わないものばかりに誘導されてしまいます。

ubuntuならvim-runtimeパッケージに、"/usr/share/vim/vim72/indent/python.vim"があるので、これを使う設定を第一にすべきでしょう(kaoriyaのvim7.2にもcygwinvimにもindent/python.vimがあるのは確認済)。

必須設定

ふたつのファイルに以下の設定内容を書くだけです。

" ~/.vimrc
syntax on
filetype plugin indent on
" ~/.vim/ftplugin/python.vim
setlocal softtabstop=4
setlocal shiftwidth=4
setlocal textwidth=80
setlocal smarttab
setlocal expandtab
setlocal nosmartindent

とりわけ、(よく検索でかかる設定例のように).vimrcなどでsmartindentしてあるとindentの動作がおかしくなるので、安全のためnosmartindentしておきます。

(4スペースインデントや80文字などの)設定はPEP-8にあわせています。

オプション設定

自分のvimの他のグローバル設定です(環境差や4ハードタブやeucなどは認めない)。

" ~/.vimrc
set modeline
set nobackup
set incsearch
set smartcase
set showmatch

set encoding=utf-8
set fileencoding=utf-8
set fileformat=unix
set tabstop=8
set columns=80

自分の~/.vimrcは、上のにこの~/.vimrcを下に加えただけのものになっています。

TB返答: Re: python用vim設定 - ラシウラ - while ("im the true Vim master"); - vimグループ

まず、indentexprはvim72/indent/python.vimでsetlocalしてます。set nosmartindentは、~/.vimrcのset smartindentを打ち消したいためにしてるものです。

after/ftpluginですが、こちらも~/.vimrcのset群を上書きしたいだけで、システム標準の設定を上書きするわけではありません。そのためafterに置くものでは無いと思うのですけど。

heap queueを自分で実装してみる

プライオリティキュー実装としてよくつかわれるpythonのheapqモジュールのソースは、ばらばらのリストをheap化するheapifyのようなものがあったり、細かい効率化などもあって、そのソースコードは結構な大きさです。

基本はそうたいそうなものではないので、訓練として自らの手で実装してみました。heapを空リストから追加前提にし、アルゴリズム部分をなるべくシンプルに書いてみると、このくらいになりました。

heap操作の理解のためのメモ

heapは、二分木の配列表現の一種:

  • インデックスが1始まりだとすると、インデックスnの子は2nと2n+1になる
    • たとえば、1の子は2と3、2の子は4と5、3の子は6と7のようにかぶることは無い
    • CやPythonのように0始まりの場合は、2n+1と2n+2
  • さらに、すべてのノードで、親の値は子の値より必ず小さい必要がある
    • 先頭が最小値
    • (そうなるように、push/popで調整する)

push操作は以下:

  • まず配列の最後に値を追加する
  • 最後をカーソルにしてループ
    • 親を見て、親のほうが大きければ、swapする。そうでなければ終了。
    • カーソルを移して終了まで繰り返す

pop操作は以下:

  • 先頭を結果として保存しておく
  • 最後の値をpopする
  • pop後空なら終了し、結果を返す
  • (そうでなければ)popした値を配列の先頭へ上書きする
  • 先頭をカーソルにしてループ
    • 子の値の小さいほうと比べ、それより大きければその子の値と入れ替える
    • 子がないか、子より小さければ終了し、結果を返す
    • カーソルをswapした子に移して終了まで繰り返す

pushは底から頭にswapしつつ上がる感じで、popは頭から底へswapしつつ下がっていく感じでしょうか。どちらのswap回数も最大log2(size)回です。