トップ 最新 追記

じじぃの日記、ツッコミ可

Twitter: @jijixi_org
Xbox Live: jijixi

初心者が書いた OCaml 入門
Spotlight tips サイト内リンク集
1970|01|02|
2003|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|11|
2011|05|
2012|01|

2006-04-01 [長年日記]

% [雑談] Perlish Magazine

日付変わって即かよ(笑

なんか素で Perl を普及しちゃってるような内容だなあ(苦笑

% [雑談] ナイタ2ッキ

たぶん 4/1 企画。 泣けすぎる。

% [雑談] フェアリアルでも 4/1 ネタ

短いパスワード危険(笑

% [雑談] ホトトギス・フィールド (はりせんかまし)

あいかわらず、単なる 4/1 ネタで終わらない味のある文章だ。

みなさん、子どもに戻って、バッターボックスに立ってみてください。とにかく遠くに飛ばそう、と思いませんでしたか?子どもの頃、野球は遠くに飛ばせば飛ばすほどヒーローになれるスポーツでした。投げる時は打たれまいと思い切り速い球を投げ込みました。そして打たれればボールを追って一直線に全力で走ったのを覚えているはずです。ベースボールを塁球と訳したのでは、塁に縛られたゲームの名前になってしまう。しかし「野球」訳したとき、それは野原でボールを追って走り回る、おおらかなゲームになったのです。

かっこ良すぎる。


2006-04-03 [長年日記]

% [game] えいご漬け (NDS)

こんなもんで英語ができるようになるとは思えん……と思いつつ、単におもしろそうだから思わず買ってしまったりした。 ちょっと流行には乗り遅れてるが(苦笑

や、わりと楽しいわ。 でも発音の練習のお題に『I love you.』とか持って来るのはやめて欲しい(笑

あー、あと文字の入力は Graffiti でできるようにして欲しいなー。 だんだん入力がかったるくなってくる (ダメ人間が極まってます)。

% [Mac][uim] 最近の MacUIM には uim-xim が含まれていたのか……

以前は含まれてなかったんで、無いもんだと思い込んでたよ。 濡れ衣着せてしまって申し訳ないことをした。 てことで、邪魔な fink 版 uim はさっさと消して、~/.xinitrc に

/Library/Frameworks/UIM.framework/Versions/Current/bin/uim-xim --engine=skk &

とか書いてやって終了……でも良いんだけど、最近の fink は X 用にごにょごにょやってくれる仕組みが付いてるので、~/.xinitrc は消して…

% cat /sw/etc/xinitrc-first-hook
xset fp+ /usr/X11R6/lib/X11/fonts/local/
xset fp+ /usr/X11R6/lib/X11/fonts/ttf_local/
xset fp rehash

xinitrc_kinput2_macim_enable=NO
/Library/Frameworks/UIM.framework/Versions/Current/bin/uim-xim --engine=skk &

こんな感じに。 xinitrc_kinput2_macim_enable を YES にしてやると (つーかそれがデフォだが) kinput2.macim を勝手に起動してくれる。 ちなみに実際の起動スクリプトは /sw/etc/xinit.d/ にあるんで、詳しくはそこと /etc/X11/xinit/xinitrc 読むのがよろしい。


2006-04-05 [長年日記]

% [Haskell] 『入門 Haskell』買うたよ

ヨドバ行ったらあったんで。 ポイント溜まってたし、助かった。 感想とかは、まあぼちぼち。 つーか、他の積ん読本をどうすんのかとか色々問題がー...orz

ちなみに買って帰ってきて袋から出したときに、帯に書いてある『Haskell プログラミングひとまわり』が『ひまわり』に見えて「すわ!?買う本間違えた!?」ってちょっぴり焦ってしまったのは内緒。 つか、ネタじゃなく素でびっくりしてしまったのは、さすがに自分でもいただけないと思ったょ。

% [Mac][uim] さようなら UIM

あかん、なんやようわからんけど、インプットフィールドが存在するアプリが軒並み起動時に虹色のグルグル出したり、X11 絡みがアホほどメモリ食ったり、困った現象続発でもう付いて行かれへんわ。 kinput2.macim 使てるときはログインしてすぐのスワップ使用量が 180MB くらいやのに、uim-xim 使てると 1GB 越えとかあり得へんやろ。

そんなわけで、skk は恋しいけども当面 UIM は諦めるわ。 AquaSKK は最近どうなんやろなあ。 でもあちらさんを使うとなると、X11 用には別個に skkinput とか入れなあかんからめんどいわ。 設定、別々やし。 それにしても、なんで fink には skkinput が入っとらんの? ええねん、わしはもう『ことえり』でええねん...orz

……そんな、エセ関西弁で語りたくなるような切ない日々。


2006-04-06 [長年日記]

% [OCaml][Haskell] 型クラスもどき

この前、型クラスって functor みたいなものとちゃうの〜?みたいなざれごとを書いたので、試しに functor 使って型クラスもどきなことをやってみようという話。

ちょっと冗長ではあるけど、そういうのをスッキリさせるには camlp4 を使えば良いわけで (いや、わしは書けんけども) 、とりあえずちょっとしたお遊び程度にはなってる感じがしないでもない。 あと、module を相互参照させる方法がよくわかんなかったんで、ordering の定義は手を抜いたりしてる。 ま、所詮お遊びだからね。

% cat typeClass.ml
module type BaseEq = sig
   type t
   val (==) : (t -> t -> bool) option
   val (/=) : (t -> t -> bool) option
end

module type Eq = sig
   type t
   val (==) : t -> t -> bool
   val (/=) : t -> t -> bool
end

module MakeEq (A : BaseEq) : (Eq with type t = A.t) = struct
   type t = A.t
   let rec (==) x y =
      match A.(==) with
      | Some f -> f x y
      | None -> not (x /= y)
   and (/=) x y =
      match A.(/=) with
      | Some f -> f x y
      | None -> not (x == y)
end

type ordering = LT | EQ | GT

module type BaseOrd = sig
   module Eq : Eq
   type t = Eq.t
   val compare : (t -> t -> ordering) option
   val (<)  : (t -> t -> bool) option
   val (<=) : (t -> t -> bool) option
   val (>=) : (t -> t -> bool) option
   val (>)  : (t -> t -> bool) option
   val max  : (t -> t -> t) option
   val min  : (t -> t -> t) option
end

module type Ord = sig
   module Eq : Eq
   type t
   val compare : t -> t -> ordering
   val (<)  : t -> t -> bool
   val (<=) : t -> t -> bool
   val (>=) : t -> t -> bool
   val (>)  : t -> t -> bool
   val max  : t -> t -> t
   val min  : t -> t -> t
end

module MakeOrd (A : BaseOrd) : (Ord with type t = A.t) = struct
   module Eq = A.Eq
   open Eq
   type t = A.t
   let rec compare x y =
      match A.compare with
      | Some f -> f x y
      | None ->
           if x == y then EQ
           else if x <= y then LT
           else GT
   and (<=) x y =
      match A.(<=) with
      | Some f -> f x y
      | None -> compare x y != GT
   and (<) x y =
      match A.(<) with
      | Some f -> f x y
      | None -> compare x y = LT
   and (>=) x y =
      match A.(>=) with
      | Some f -> f x y
      | None -> compare x y != LT
   and (>) x y =
      match A.(>) with
      | Some f -> f x y
      | None -> compare x y = GT
   and max x y =
      match A.max with
      | Some f -> f x y
      | None -> if x >= y then x else y
   and min x y =
      match A.min with
      | Some f -> f x y
      | None -> if x <= y then x else y
end

module Eq_int =
   MakeEq (struct
              type t = int
              let (==) = Some (Pervasives.(=))
              let (/=) = None
           end)

module Ord_int =
   MakeOrd (struct
               module Eq = Eq_int
               type t = Eq.t
               let compare = Some begin fun x y ->
                  let r = Pervasives.compare x y in
                  if Pervasives.(=) r 0 then EQ
                  else if Pervasives.(<) r 0 then LT
                  else GT
               end
               let (<=) = None
               let (<)  = None
               let (>=) = None
               let (>)  = None
               let max  = None
               let min  = None
            end)
% ocamlc -c typeClass.ml
% ocaml typeClass.cmo
# open TypeClass.Eq_int;;
# open TypeClass.Ord_int;;
# 1 == 2;;
- : bool = false
# max 1 2;;
- : TypeClass.Ord_int.t = 2

BaseEq, Eq, MakeEq の三つセットがクラスで、Eq_int がそのインスタンスっていうイメージ。 Ord は Eq クラスを継承するので、内部に Eq 型のインスタンスを持つ。 Base なんちゃらの関数が option 型になってるのは、必要なものだけ定義すれば良いように。 そのおかげでほとんど同じ signature を二つ書かなきゃならないのは格好悪いが、そこはプリプロセッサががんばれ、と(苦笑

でもやっぱあれだね、もしこういう仕組みがあっても、関数オーバーロードが無いと不便な感じはするね。 いちいち open するのもどうかと思うし。 Haskell みたいに関数を中置演算子として使う方法があれば、だいぶ違うんだけど。

% [FreeBSD] ついに! FreeBSD Java 1.5待望のオフィシャルリリース (MYCOM PCWEB)

世間は Boot Camp の話で持ち切りだが、そんなもんよりこっちの方が大ニュースでしょうに (偏った意見)。 これで地獄のようなビルド時間を経なくても JDK が利用できるようになるんだから、嬉しい人はたくさんいるに違いない。

わしもさっそく入れよう。 ……特に必要は無いけども(ぉぃ


2006-04-07 [長年日記]

% [PC][雑談] ハッシュと連想配列 (どーんとやってみよう)

わしも似たような疑問は感じてたが、k.inaba さんの説がわりとしっくり来る感じがした。 あと、さりげなくはてなキーワード『連想配列』あたりの説明がすっきりしてる気もする。

まあ、『連想配列』が広義の意味なんだとしても、『ハッシュアルゴリズムを使った実装が多いからハッシュと呼ぶことが多い』というのが微妙に納得いかなくて、じゃあもし二分木を使った実装が多かったら『二分木』って呼ぶのかよ〜みたいなひねくれた気持ちはあったりなかったり。 hash table だとか hash map だとか、なんかあるだろーと。

……だからって OCaml みたいに Hashtbl なんて名前にするのもどうかと思うが(注:オチです)。

% [Haskell] 入門 Haskell 斜め読み

型とモナドのところだけはちゃんと読んだ。 …が、残念ながらすでに何となく理解している程度以上の突っ込んだ内容は無かったみたい。 ま、『入門』だもんなあ。 むしろ悔しいのは、もっと早くこの本が存在していれば、わしがあーだこーだ試行錯誤して悩んでウンウン唸るまでもなく理解できたかも知れないのに……って点だね(苦笑)。 結構わかりやすく書いてあるとは思う。 値段も手頃だし、入門書としては良い感じかと。

せっかくだから苦言も呈しておくと、未説明の用語が突然出てくる箇所があるのがちょっといただけない。 例えば 1.6 で『高階関数』って言葉が出てくるけど、しばらく先に進まないと (2.4 辺り) 用語の説明が無いので、ほんとに『はじめて学ぶ』人なら「???」な感じになる気がする。

あとは索引のでたらめさに度肝を抜かれた(笑)けど、これは著者の責任ではないと思うんで仕方ない。

% [雑談] 増刷待ちとかって良くわからん

2ch みてると特にそうなんだけど、誤植が多いから修正された増刷版を待つぜーみたいなこと言う人って、結局その本をそんなに欲しいと思ってないんだろうなと思う。 誤植があるのがわかってて、かつ、それが気になるんだったら、どんどん自分で正しいのを書き込んでやれば良いじゃない。 本なんて、読みたいと思った時に読まなかったら意味無いでしょ。

今まさにその本を読む事で、何かすばらしいものが得られるかもしれないのに、本質的じゃないミスを嫌って数ヶ月待つなんてことは時間の無駄でしかないと思うね。 その本が出る事を『待っていた』なら、ちょっとした誤植だとかを気にして買い控えたりしちゃいけない。

もちろん本質的な内容に問題があるか否かを 2ch なんかでリサーチするのは良いよ。 無駄な買い物なんかしたくないもんね。

本日のツッコミ(全2件) [ツッコミを入れる]

% 向井 [いや、でも、けっこうたくさん誤植を指摘されておりましてヘコみます…… 高階関数はまったく気付いてませんでした。あとで..]

% jijixi [お疲れさまです。 誤植の無い本なんてありませんから、適当にゴメンって言っとけば良いと思いますよ(笑 以下雑談。 自分..]


2006-04-08 [長年日記]

% [雑談][game] ソフトの数だけ興奮がある「セガゲーム」アーケード編 (Tech 総研)

via del.icio.us/otsune.

そうそう、セガゲームにはまった原因の半分はBEEPです(笑)。

に笑う。ある意味セガのプロパガンダ紙に近かったからなあ(苦笑)。 あと、細かいツッコミすると、『Beep』と表記するのが正しい。

アフターバーナーはメロディーがなくてベースしかなかったのでとらなかったですね(笑)。

そのネタを出すなら、Beep のソノシートにメロ入り版が入ってた事実を挙げるべきだな。 あと、どっかから出てたサントラにも入ってたような気がする。 わしはどんなメロディだったか憶えてるぜ (自慢になりません)。

あと…

音楽だとアウトランが走る風景でロックやラテンなど次々と曲が変わるのですが、ポップスしか知らない自分には衝撃的でした。

アウトランじゃなくアウトランナーズかなんかと混同してると思われ。 アウトランは最初に音楽決めたら、あと変わらないし。

% [PC][独り言] AVRマイコン・リファレンス・ブック

リファラ巡りしてたら、こんなもの発見……ちょっと欲しい。

% [Scheme][Gauche][OCaml] たらいまわしといえば Lisp (どーんとやってみよう)

なんか知らんが巷では、たらいまわすのが流行ってるらしいが、Haskell 速えーとか言ってっけどバカヤロウ OCaml の方が速いだろうがー!!つーて、OCaml 版を書いてやろうと思ったところ、向井さんが先にやってくれたんで楽をした。

……ってアレ? Haskell の方が速いのか、意外 (tak.mlx のときの 87% cpu てのがちと気になるが)。 つか、Haskell 版のバイナリのでかさって一体(苦笑

実はこのリストで特筆すべきなのは、Gauche と、OCaml のコンパイルしない版 (ocaml コマンドのやつね) なんじゃないかと思った。 特に Gauche 版は動的型付け言語の中では、ずば抜けて速いのがスゴイ。

ところで Perl や Ruby と同じようにハッシュテーブル使ったらどうなんの?ってことで、tak.scm を改造してメモ版 tak.rb を参考にこんなん書いてみると……

% cat tak.2.scm
(define memo (make-hash-table 'eqv?))
(define (tak x y z)
  (if (not (hash-table-exists? memo x))
    ((setter ref) memo x (make-hash-table 'eqv?)))
  (if (not (hash-table-exists? (ref memo x) y))
    ((setter ref) (ref memo x) y (make-hash-table 'eqv?)))
  (if (hash-table-exists? (ref (ref memo x) y) z)
    (ref (ref (ref memo x) y) z)
    (let1 ret (if (<= x y)
                y
                (tak (tak (- x 1) y z)
                     (tak (- y 1) z x)
                     (tak (- z 1) x y)))
          ((setter ref) (ref (ref memo x) y) z ret)
          ret)))

(let-optionals*
  (map string->number *argv*) ((x 10) (y 5) (z 0))
  (format #t "tak(~A, ~A, ~A) = ~A\n" x y z (tak x y z)))

ref のネストっぷりが死にそうだが(苦笑)、ともあれ結果を……

% time gosh tak.2.scm 100 50 0
tak(100, 50, 0) = 100
gosh tak.2.scm 100 50 0  0.77s user 0.05s system 91% cpu 0.904 total

% time gosh tak.scm 100 50 0
tak(100, 50, 0) = 100
gosh tak.scm 100 50 0  0.06s user 0.03s system 73% cpu 0.114 total

% time perl ./tak.pl 100 50 0
tak(100, 50, 0) = 100
perl ./tak.pl 100 50 0  0.34s user 0.04s system 87% cpu 0.429 total

% time ruby ./tak.rb 100 50 0
tak(100, 50, 0) = 100
ruby ./tak.rb 100 50 0  0.42s user 0.05s system 87% cpu 0.535 total

ハッシュテーブルの性能は Ruby や Perl に負けてる模様 (わしの書き方がアホなんでなければ)。

% [Scheme][Gauche] たらいまわしの続き

よく考えたら、律儀に多次元にする必要なんて無いじゃん。 キーはリストで良いだろよ。

% cat tak.3.scm
(define memo (make-hash-table 'equal?))
(define (tak x y z)
  (let1 m (ref memo (list x y z) #f)
        (if m
          m
          (let1 ret (if (<= x y)
                      y
                      (tak (tak (- x 1) y z)
                           (tak (- y 1) z x)
                           (tak (- z 1) x y)))
                ((setter ref) memo (list x y z) ret)
                ret))))

(let-optionals*
  (map string->number *argv*) ((x 10) (y 5) (z 0))
  (format #t "tak(~A, ~A, ~A) = ~A\n" x y z (tak x y z)))
% time gosh tak.3.scm 100 50 0
tak(100, 50, 0) = 100
gosh tak.3.scm 100 50 0  0.36s user 0.04s system 89% cpu 0.453 total

これで Perl や Ruby 並みになった。 どうでも良いけど、hash-table-put! (上で使ってるのは setter ref だけど) の返り値が #<undef> なのが微妙に使いづらかった。(おかげで余計な let1 が必要になってるわけで)

% [Ruby] たらいまわしのおまけ

Gauche でうまくいったのに味をしめて Ruby もキーをリスト (つーか配列) にしてみた……

@tak = {}
def tak(x, y, z)
   mem = @tak[[x,y,z]]
   if mem then mem
   else
      @tak[[x,y,z]] =
      if x <= y
         y
      else
         tak(tak(x-1, y, z),
             tak(y-1, z, x),
             tak(z-1, x, y))
      end
   end
end
x, y, z = ARGV.size == 3 ? ARGV.map{|s| s.to_i } : [10, 5, 0]
puts "tak(#{x}, #{y}, #{z}) = #{ tak(x, y, z) }";

……ら、かえって遅くなったよ(苦笑

% time ruby tak.rb 100 50 0
tak(100, 50, 0) = 100
ruby tak.rb 100 50 0  1.05s user 0.05s system 84% cpu 1.311 total

% [OCaml] たらいまわし、えーい、もうヤケだ

ここまで来たら OCaml のハッシュテーブル版だってやらねばなるまい。

let memo = Hashtbl.create 0
let rec tak x y z =
   try
      Hashtbl.find memo (x,y,z)
   with Not_found ->
      let ret =
         if x <= y
         then y
         else tak (tak (x - 1) y z)
                  (tak (y - 1) z x)
                  (tak (z - 1) x y)
      in
      Hashtbl.add memo (x,y,z) ret;
      ret

open Array
open Sys
let _ =
   let (x, y, z) =
      if length argv = 4
      then (int_of_string argv.(1), int_of_string argv.(2), int_of_string argv.(3))
      else (10, 5, 0)
   in
   Printf.printf "tak(%d, %d, %d) = %d\n" x y z (tak x y z)
% time ocaml tak.2.ml 100 50 0
tak(100, 50, 0) = 100
ocaml tak.2.ml 100 50 0  0.24s user 0.04s system 86% cpu 0.320 total

% time ocaml tak.ml 100 50 0
tak(100, 50, 0) = 100
ocaml tak.ml 100 50 0  0.12s user 0.03s system 81% cpu 0.181 total

lazy 使ったのよりは遅いが、スクリプト言語連中には勝った。

ところで向井さんが書いたのにはバグっつーか typo があったりしますよ?(ボソ

本日のツッコミ(全7件) [ツッコミを入れる]

Before...

% jijixi [ついでに言うと、*argv* ってのも初めて知りましたね(苦笑 コマンドラインから引数を得るには main 関数を定..]

% 向井 [ありゃ、私が書いたコードでは Sys と Array は open してなったので typo には気付いてませんでし..]

% _ [> まあ、手柄は向井さんのものですが ぎゃー、本当だ。ホント感謝です。>向井さん]


2006-04-09 [長年日記]

% [雑談] スタックオーバーフローの解析結果

みんな、スタックが溢れて悔しい思いをしたときには、これを思い出すんだ。

スタックオーバーフローの94%は乙女心で出来ています

スタックオーバーフローの6%は媚びで出来ています

きっと悔しさが紛れるはずだから。(ほんとかよ)

% [雑談] 関数の解析結果

そんな神秘的なものだったとわ!!

関数の49%は魔法で出来ています

関数の39%は純金で出来ています

関数の8%は成功の鍵で出来ています

関数の4%は理論で出来ています

理論はたった 4% かよ。

% [雑談] C++の解析結果

C++の68%は食塩で出来ています

C++の9%は気の迷いで出来ています

C++の8%はミスリルで出来ています

C++の8%は言葉で出来ています

C++の7%は濃硫酸で出来ています

気の迷いがわりと少ないな(爆

% [Python][雑談] 以前は特に気にならなかった Python の仕様

関数型言語に慣れた今となっては、非常にハマりやすい罠と化した。

>>> def f(x,y):
...     x + y
...
>>> f(1,2)

>>> def g(x,y):
...     return x + y
...
>>> g(1,2)
3

Python では return を使わない限り関数は値を返さない。 Python の嫌いなところが増えた(苦笑

あと、if 文や try 文は一応値を持ってるみたいなんだけど…

>>> a,b = 1,0
>>> if a > 0:
...     a
... else:
...     b
...
1

…その値を使う方法がわかんないとか。

>>> v = if a > 0:
  File "<stdin>", line 1
    v = if a > 0:
         ^
SyntaxError: invalid syntax

Ruby でも OCaml でも Scheme でも当たり前にやってることができないとストレス溜まる。


2006-04-10 [長年日記]

% [PC][Java] 今日の新言語『The Scala Programming Language

via Matzにっき

また JVM 使うタイプかよ〜と思いつつ、一応関数型とオブジェクト指向の混血ってことで好みには合いそうな気配がしたんで試してみる。 ……対話環境が使いにくい。 複数行の入力ができないのってちょっとどうよ?

や、それよりもここですよ。

Note that subtyping of generic types is invariant. This means that if we have a stack of characters of type Stack[Char] then it cannot be used as an integer stack of type Stack[Int]. This would be unsound because it would enable us to enter true integers into the character stack.

暗黙の変換キター!! ……ヤメレ...orz

と思ったら、そんなビビる必要も無いのか。

To conclude, Stack[T] is only a subtype of Stack[S] iff S = T. Since this can be quite restrictive,

ちゃんとこんな↓ときはエラーになるし。

scala> val i : Int = 1.0
<console>:4 error: type mismatch;
 found   : scala.Double(1.0)
 required: scala.Int
  val i : Int = 1.0
                ^

でもこんな↓風になるのは…

scala> val i : Int = 1
i: scala.Int = 1

scala> val f : Double = i
f: scala.Double = 1.0

ちょっと微妙かも。 整数が知らないうちに浮動小数点数に変わってるのって、わりとバグの元な気がするんだけどね。 これで型安全って言えるのかな。 ……うーん、Int → Double はあっても Double → Int は無いんだから、いずれはどっかで型エラーになるのかな。 それはそれで、どこが間違ってるか探すのがめんどくなりそうだ。 こういうこと考えてると、Haskell の数値関係の仕様ってややこしいけどよくできてるのかなって気もしてくる (あれがうまくいくのは遅延評価だからこそって気もするけど)。

ともあれ、パターンマッチにちょっと工夫があったり (Regular Expression Patterns) おもしろそうな部分はいろいろある。 ちまちまいじってみよう。

Examples のページに

Tip: Unix users should prepend the word ledit to the above command line in order to benefit from the line editing functions in the interactive Scala interpreter.

とか書いてあって微笑ましい。 もう ledit は必需品ですな。

% [Scala] Scala の型推論

馴染みのある OCaml のものから比べると、ちょっと見劣りする感じ。

まず関数の引数に対する型指定を省略できない。

scala> val f = (x => x + 1)
<console>:4 error: missing parameter type
  val f = (x => x + 1)
           ^

scala> val f = (x:Int => x + 1)
f: (scala.Int) => scala.Int = <function>

どうも多相型というものが無いようなので、そもそも引数の型を推論するのが無理なのかも知れない。 上のような例なら x の型は Int を一つ取る (+) というメソッドを持つオブジェクトじゃなきゃならないけど、そういう型を表す方法が無いっぽい。

まあ Java の Generics に相当する機能はあるので、実用上の不利は無いのかも知れない。 いちいち型指定しなきゃならないのはかったるいが。 変数の型指定はほとんど書く必要が無いので、型推論が無いよりははるかにマシ。

% [Scala] Scala のパターンマッチ

なかなかおもしろい。 Pattern Matching のページを見ると、こんなことが書いてある。

The third case consists of a typed pattern; it matches against any integer and binds the selector value x to the variable y of type integer.

どうも Any という型が OCaml で言うところの 'a であるらしく、しかも OCaml 初心者が大抵ハマる (少なくともわしだけではないはずだが) ワナである…

let f x =
   match x with
   | i:int -> i + 1
   | f:float -> f +. 1.0
   | s -> s

みたいな (OCaml ではありえない) 関数が書けてしまうのであった。

% cat main.scala
object Main extends Application {
   def test(x:Any):Any =
      x match {
         case i:Int => i + 1
         case f:Double => f + 1.0
         case s => s
      }
   Console.println(test(1))
   Console.println(test(1.0))
   Console.println(test("hoge"))
}
% scalac main.scala
% scala Main
2
2.0
hoge

これはおもしろい。 さらに case class というのを使うと OCaml における variant type のようなことができるみたい。 多分、例に挙がってる、

abstract class Term
case class Var(name: String) extends Term
case class Fun(arg: String, body: Term) extends Term
case class App(f: Term, v: Term) extends Term

って定義は、OCaml で言えば、

type term =
| Var of string
| Fun of string * term
| App of term * term

みたいなものだと思われる。

% [Scala] 暗黙の変換

Views と言うのがその正体らしい。 基本的にはあらかじめそう設定しておかないと、暗黙の変換は行なわれないようだ。 んで、基本的な型についてはこのページの図のように、View が定義されているということみたい。

でもやっぱり何だか Long → Float は余計なような気がするけどなあ。

% [Scala] カリー化

ドキュメントに嘘がある。 と言うか仕様変更に追随できてないのか。

scala> def f(x:Int)(y:Int) = x + y;
f: (scala.Int)(scala.Int)scala.Int

scala> def g = f(1);
<console>:5 error: missing arguments for method f in object line0$object;
prefix this method with `&' if you want to treat it as a partially applied function
  def g = f(1);
           ^

scala> def g = &f(1);
g: => (scala.Int) => scala.Int

scala> g(2)
line14: scala.Int = 3

こういう仕様だってことは、もしかして val と def では違う名前空間使うのかな?と思ったんだけど、そういうわけでもないらしい。

scala> val g = 0
g: scala.Int = 0

scala> g
line16: scala.Int = 0

scala> &g
<console>:5 error: `&' must be applied to method type; cannot be applied to => scala.Int
  val line17 = &g
                ^

オプショナル引数かなんかの絡みなのかねえ。 なんか def じゃなく val で関数定義すると…

scala> val f = (x:Int) => (y:Int) => x + y
f: (scala.Int) => (scala.Int) => scala.Int = <function>

scala> f(1)
line25: (scala.Int) => scala.Int = <function>

こうだったりするのが微妙に納得いかないような……

% [Scala] カリー化の続き

よく見ると、def 使うときと無名関数を val で束縛するときでは型が違ってるな。

scala> def f1(x:Int)(y:Int) = x + y;
f1: (scala.Int)(scala.Int)scala.Int

scala> val f2 = (x:Int) => (y:Int) => x + y
f2: (scala.Int) => (scala.Int) => scala.Int = <function>

んで、この f1 を &f1 にすると…

scala> &f1
line33: (scala.Int) => (scala.Int) => scala.Int = <function>

f2 と同じ型になる。 def による定義は最初はカリー化されていなくて、& を使う事でカリー化されたものを得られるという感じだろうか。 ちなみにこんな↓風に無名関数を書こうとするとエラーになるんだよな。

scala> val f3 = (x:Int)(y:Int) => x + y
<console>:2 error: malformed formal parameter list
val f3 = (x:Int)(y:Int) => x + y
                ^

def で最初からカリー化された関数定義をするには (ちょっと気持ち悪いけど) こうすれば良いみたい。

scala> def f4 = (x:Int) => (y:Int) => x + y;
f4: => (scala.Int) => (scala.Int) => scala.Int

scala> f4(1)
line37: (scala.Int) => scala.Int = <function>

それにしても、(どっちの方法で定義しても) 関数適用のときに引数を一つずつカッコで囲まなきゃならないのは気持ち悪いなあ……

scala> f1(1)(2)
line35: scala.Int = 3

まあ、おかげで引数が複数あるメソッドも、メソッドチェーンできるのはありがたいけど。

scala> f1(1)(2).toString
line46: java.lang.String = 3

% [Scala] リストの内包表記 (ついでに type alias)

あー、なんかわりと気に入りつつある。 文法にヘンテコさは感じるけど、必要な機能はだいたい揃ってるし、Java のクラスも普通に触れるとなると F# よりもおもしろいかも知れん。 F# いじってると、どうしても『劣化 OCaml』って言葉が頭をよぎるしなあ(苦笑

ってことで、内包表記。 と、その前に、Scala Library Documentation のページを見ると、いかにもリストリテラルとして [1,2,3] みたいなのが使えるように見えるんだが、Generics の型表記に [ ] を使うようにしたからなのか、現在はこの表記は存在しない模様。 今はリストリテラルは List(1,2,3) みたいに書く。 さらに言えば、配列リテラルは Array(1,2,3) でタプルリテラルは Tuple(1,2,3) になる。 これはこれで一貫してて良いのかも。

scala> val lst = for (val i <- List.range(0,10000); i < 10) yield { i * 2 }
lst: scala.List[scala.Int] = List(0,2,4,6,8,10,12,14,16,18)

ともあれ、こんな感じ。 内包表記というよりは for 文を使ったリスト生成だけど、for の文法が内包表記的だから良いんだろう。

あとリスト絡みでは、(::) が case class として存在してるので、パターンマッチでは x::xs みたいなパターンが使える。 んで、[] (空リスト) の代わりになるのは Nil。 一応 (::) は演算子としても使えるみたい。

scala> 1 :: List(2,3)
line5: scala.List[scala.Int] = List(1,2,3)

scala> List(1,2) ::: List(3,4)
line4: scala.List[scala.Int] = List(1,2,3,4)

みたいなのもある。

scala> List(1.0,2.0) ::: List(3,4)
line8: scala.List[scala.AnyVal] = List(1.0,2.0,3,4)

みたいなこともできて、ちょっと気持ち悪い。

ちなみに String は List[Char] の別名みたい。 別名の定義は type を使ってできる。

scala> type Hoge = String
defined type alias Hoge

scala> type Fuga = Array[Hoge]
defined type alias Fuga

なんか今日は完全に Scala 特集だなあ(笑

% [Scala] その他もろもろ

おお、シンボルがあるぞよ。

scala> 'x
line13: scala.Symbol = 'x

scala> new Symbol("hoge")
line24: scala.Symbol = 'hoge

他には Option 型とか。

scala> val v = Some(1)
v: scala.Some[scala.Int] = Some(1)

scala> (v:Option[Int]) match { case Some(n) => n; case None => 0 }
line26: scala.Int = 1

ストリーム型。

scala> def from(n:Int):Stream[Int] = Stream.cons(n, from(n + 1));
from: (scala.Int)scala.Stream[scala.Int]

scala> val s = from(0)
s: scala.Stream[scala.Int] = Stream(0, ?)

scala> s.take(10).toList
line32: scala.List[scala.Int] = List(0,1,2,3,4,5,6,7,8,9)

うまく有限のストリームを作る方法がわかんなくてきちんと確かめてないんだが、なんとなく破壊的じゃない作りな気がする。

% [Scala] ストリームの続き

アホだ、わし。 自分で答え出しといて気付いてないよ...orz

take で帰ってくるのが部分ストリームなわけだから、それを使って実験すりゃ良いんじゃないか。

scala> def from(n:Int):Stream[Int] = Stream.cons(n,from(n+1));
from: (scala.Int)scala.Stream[scala.Int]

scala> val s = from(0).take(10)
s: scala.Stream[scala.Int] = Stream(0, ?)

scala> s.length
line15: scala.Int = 10

てことで準備完了。 んで、次に OCaml の Stream なら中身が無くなりそうな操作をしてみる。

scala> s.foreach(x => Console.println(x))
0
1
2
3
4
5
6
7
8
9
line16: scala.Unit = ()

さてどうなっただろうか?

scala> s
java.lang.OutOfMemoryError: Java heap space

待てーーー!!! くそー、一体なんじゃこりゃ。

scala> s.length
line18: scala.Int = 10

scala> s.head
line19: scala.Int = 0

一応、foreach が破壊的操作でないことは確かなようだが。

しかしなぜ out of memory なんだ。 さっき失敗してスタックオーバーフローさせちゃった後遺症かなあ。 VM は起動しなおしてるのに。

OS 再起動したら直るかしら……

take した部分ストリームを扱ってるけど、一旦評価しちゃうと表示するときに元の無限ストリームまで評価しにいっちゃう……みたいなバグっぽい気配がしなくもない。 でも Apple の JavaVM もどこまで信用して良いもんだかわからんしなあ…… 良いや、もう再起動しよう。

% [Scala] OutOfMemoryError のその後

再起動したけど、当然のように症状は同じ。 やっぱ対話環境のバグくさいなあ。

ただ、値を表示しようとしなければ特に問題は無いみたいなんで、普通に使う分には不具合は無さそう。 対話環境を使うときのバッドノウハウとして憶えておこう。

  • 無限ストリームから take で部分ストリームを切り出しても、一旦それに foreach などの全体を評価するメソッドを使うと、その値自体を表示しようとした時点でメモリを食いつぶすよ。

あとこれ以外にも、どうも Stream の実装にはまだ甘いところがある気がする。 特に filter メソッド。 だって見てよこれ↓

scala>  val infs = from(0)
infs: scala.Stream[scala.Int] = Stream(0, ?)

scala> val filts = infs.filter(x => x < 10)
filts: scala.Stream[scala.Int] = Stream(0, ?)

scala> val takes = filts.take(10)
takes: scala.Stream[scala.Int] = Stream(0, ?)

scala> takes.length
java.lang.StackOverflowError
        at scala.Stream$class.filter(Stream.scala:185)
        at scala.Stream$$anon$1.filter(Stream.scala:31)
         (以下略)

上の例でどんなことが起こってるか想像すると、

  1. infs の中身は (0,1,2,3,4,5,6,7,8,9,10,...) の無限ストリーム
  2. filts の中身は (0,1,2,3,4,5,6,7,8,9,?,...) の無限ストリーム。
    • filter に与えた関数が false を返す値に相当する部分がどうなってるのかが全く不明 (想像としては単に次の要素を見にいくだけの処理かな)
  3. takes の中身は (0,1,2,3,4,5,6,7,8,9) の有限ストリーム
    • なんだけど、どうやら take で切り出しても実際は元のストリームを共有するらしく、しかも length は 9 の次 (filts の ? の部分) まで見にいってしまうみたい (その結果無限ループ)

ちなみにここで、

scala> val takes = filts.take(9)
takes: scala.Stream[scala.Int] = Stream(0, ?)

scala> takes.length
line57: scala.Int = 9

これだと大丈夫だったりする。 はっきり言って、今のままだと filter メソッドはおっかなくて使えない。 少なくとも、filter に与えた関数が false を返す場合にちゃんと計算が止まってくれないと。 filter の返り値を Stream[a] じゃなく Stream[Option[a]] にしちゃえば良いと思うけどねえ。 いや、別に None じゃなく null が入ってたって良いけどさ。 ちゃんと止まってさえくれれば。

% [Scala] filter が悪いわけじゃなくて length が悪いのか?

うーん、多分 filter の実装もあんまし良くないんだろうけど、filter だけのせいとも言えないのかなあという気もしてきた。

OCaml の Stream.from で作ったストリームは None が一度でも出てきた時点で終了なんだけど、Scala の Stream#filter はそうじゃなくて、条件が false になるときは飛ばして次を見にいく仕様なわけだよね。 だから、

(* OCaml *)
# let s = Stream.from (fun x -> if x mod 2 = 0 then Some x else None);;
val s : int Stream.t = <abstr>
# Stream.npeek 10 s;;
- : int list = [0]
// Scala
scala> val infs = from(0)
infs: scala.Stream[scala.Int] = Stream(0, ?)

scala> val filts = infs.filter(x => x % 2 == 0)
filts: scala.Stream[scala.Int] = Stream(0, ?)

scala> val takes = filts.take(10)
takes: scala.Stream[scala.Int] = Stream(0, ?)

scala> takes.toList
line4: scala.List[scala.Int] = List(0,2,4,6,8,10,12,14,16,18)

こんな感じで、そもそも用途が違う。 だから、x < 10 みたいな条件の場合、10 以降の要素が無限ループになっても仕方ないとも言える。

実装を見たわけじゃないから断言はできないけど、多分 length が長さを判断するマーカかなんかが『次の要素』に存在して、でも filter が false で飛ばす部分にはそれを保持する機能が無いんだろう。 だから、先のエントリのような例だと 10 個目以降の要素に金輪際そのマーカが出てこないから length が止まらない。

……あれ、やっぱ filter が悪いのか? いや、そもそも Stream の内部構造の設計が甘いのか? take で切り出した Stream は長さをメンバに持っちゃえば良いんじゃないかと思うが、それだとアドホックで嫌なのかな。

あー、ソース読みたくなってきた。 いかん、いかんぞ。 寝れなくなる。

% [Scala] スコープ

ソース読みに走るのだけは我慢したが、いまだにちまちまやってるダメ人間。 もう寝ないと(泣

ローカル変数とかどうすんのかなー?という疑問があったんだが、特別何かそれ用の構文があったりとかはしないみたい。 スコープを区切りたいところを適当にブレースで囲めば良いようだ。

scala> val s = { def f(n:Int):Stream[Int] = Stream.cons(n,f(n+1)); f(0); }
s: scala.Stream[scala.Int] = Stream(0, ?)

とか。 ちゃんとブレースの囲み自体が値を返す。 こんなとか。

object ScopeTest extends Application {
   val a = (x:Int) => {
      val b = "hoge"
      for (val i <- List.range(0,x)) yield {
         Console.println(b)
      }
   }
   a(3)
}

なんか扱いとしてはクロージャのような感じだけど。

% [Scala] メソッド呼び出しは空白区切りでも良いみたい

……と言っても引数の区切りじゃなく、メソッドの区切り。 要するにドットの代わりに空白を使う。

% cat MethodTest.scala
object MethodTest extends Application {
   class Hoge {
      def p(s:String) = {
         Console println(s)
         this
      }
   }
   val o = new Hoge
   o p("hoge") p("fuga")
}
% scalac MethodTest.scala
% scala MethodTest
hoge
fuga

なんかすごく不思議な感じ(苦笑

まあ、Ruby の演算子なんかは、ある意味こういう感じだけども、メソッド全てでこういう書き方できるってのはちょっと新鮮。

あと、ついでだから書こう。 インスタンス変数の定義は val じゃなく var を使う。 紛らわしい(笑

scala> class Hoge { val a = 0; var b = 0 }
defined class Hoge

scala> val o = new Hoge
o: line10$object.Hoge = line10$object$Hoge@f903f9

scala> o.a
line12: scala.Int = 0

scala> o.b
line13: scala.Int = 0

scala> o.a = 1
<console>:5 error: assignment to non-variable
  val line14 = o.a = 1
                   ^

scala> o.b = 1
line15: scala.Unit = ()

scala> o.b
line16: scala.Int = 1
本日のツッコミ(全1件) [ツッコミを入れる]

% lethevert [無限リストで、安易にfilterを使ってはいけないというのは、結構基本的なTipsですよ。 これとか↓ http:/..]


2006-04-11 [長年日記]

% [Scala][ツッコミ] Scala の Stream 問題

lethevert さんからツッコミを受けた。 「安易にfilterを使ってはいけない」というのは確かにわかりました。 や、挙げられた URI のどの部分にそれが書いてあるのかは、ちょっと読み取れなかったんですが(汗)、今日も暇な時間にいろいろ考えてたので、たぶん理解できたつもりです。

昨日の失敗は filter を OCaml の Stream.from と同じように考えて使ってしまったことにも敗因はあります。 どっちにしても、残り全部が false になっちゃうようなフィルタは使っちゃいけないんでしょうね。

(ここからは、lethevert さんへの返事ではなく、いつもの独り言です。)

ただ、やっぱりそれでも Scala の Stream には設計 (…か実装かはわかりませんが) の不備があるように思えます。 昨日の例をもう一度書くと……

scala> def from(n:Int):Stream[Int] = Stream.cons(n,from(n+1));
from: (scala.Int)scala.Stream[scala.Int]

scala> val infs = from(0)
infs: scala.Stream[scala.Int] = Stream(0, ?)

scala> val filts = infs.filter(x => x < 10)
filts: scala.Stream[scala.Int] = Stream(0, ?)

scala> val takes = filts.take(10)
takes: scala.Stream[scala.Int] = Stream(0, ?)

ここで、infs は 0 から始まり 1 ずつ増加する無限ストリームです。 filts は infs に対して x < 10 を満たす値 (つまり 0 から 9 の 10 個) だけを選択した無限ストリームです。 takes は 0 から 9 までの 10 個の要素を持つ有限ストリームです。 そして、この takes に対して length メソッドを使うと無限ループします。

素朴な連結リストの実装なら、take(10) した時点で 9 が head にあたるセルの tail 部分に空リストを入れたりするんでしょう。 その場合 length は再帰的に要素を手繰っていって、空リストが現れるまでの再帰回数を数えれば良いということになります。 そのような実装であれば、takes.length が無限ループになることは無いはずです。 実際に有効な値は 10 個あるわけですから、10 個目の head を手繰った時点で tail は空ストリームとして扱わないと変です。 もちろん、take(11) として得た部分ストリームであれば、無限ループしてもしかたないと思いますが。

例えば、Haskell ではこんな風になります。

Prelude> length (take 10 [x | x <- [0..], x < 10])
10
Prelude> length (take 11 [x | x <- [0..], x < 10])
{Interrupted!}

take 10 の場合はきちんと計算が止まりますが、take 11 の場合は (11 個目以降の値が実質存在しないので) 無限ループになります。 これは直感的にも納得がいきます。 でも、Scala の Stream は無限ループするかしないかの境界が直感に反します。 (ところで、こういう場合の『ちょっかん』は『直観』の方が正しいんでしょうか?)

そんな意味で、やっぱり Scala の Stream は作り込みがまだ『甘い』んじゃないかと思うわけです。

とは言え、実際に何か作る時に、こんなことが気になるような場面はほとんど無さそうな気はします。 だから、あまり気にするようなことでも無いのかも知れませんね(苦笑

% [Scala] def と val

今日も Scala の日(苦笑

def でも val でも関数の定義はできてしまうんだが、二種類用意されてるってことは何かが違うはずで、じゃあどう違うんだ?という話。

その一
基本的には val は値で def は関数である

まあ、当たり前と言えば当たり前。 感覚的には OCaml のオブジェクトにおける method と val の関係に似てる。

scala> class Fuga { val f = Console.println("fuga"); def g = Console.println("hoge"); }
defined class Fuga

scala> val o = new Fuga
fuga
o: line5$object.Fuga = line5$object$Fuga@ba67ec

scala> o.f
line7: scala.Unit = ()

scala> o.g
hoge
line8: scala.Unit = ()

こういう違い。

その二
def はオーバーロードが可能

逆に言うと val ではできない。

scala> class Def { def f(n:Int) = n + 10; def f(s:String) = s }
defined class Def

scala> val o = new Def
o: line9$object.Def = line9$object$Def@30c68b

scala> o.f(1)
line11: scala.Int = 11

scala> o.f("foo")
line12: java.lang.String = foo
scala> class Val { val f = (n:Int) => n + 10; val f = (s:String) => s; }
<console>:4 error: f is already defined as value f
  class Val { val f = (n:Int) => n + 10; val f = (s:String) => s; }
                                             ^
<console>:4 error: f  is already defined as value f
  class Val { val f = (n:Int) => n + 10; val f = (s:String) => s; }
                                             ^
<console>:4 error: ambiguous reference to overloaded definition,
both value f in class Val of type => (scala.Int) => scala.Int
and  value f in class Val of type => (java.lang.String) => java.lang.String
match expected type ?
  class Val { val f = (n:Int) => n + 10; val f = (s:String) => s; }
                  ^
<console>:4 error: ambiguous reference to overloaded definition,
both value f in class Val of type => (scala.Int) => scala.Int
and  value f in class Val of type => (java.lang.String) => java.lang.String
match expected type ?
  class Val { val f = (n:Int) => n + 10; val f = (s:String) => s; }
                                             ^
<console>:4 error: value f is defined twice
  class Val { val f = (n:Int) => n + 10; val f = (s:String) => s; }
                                             ^

ちなみに…

scala> class Foo { def f(n:Int) = n + 10; val f = "hoge" }
defined class Foo

scala> val o = new Foo
o: line20$object.Foo = line20$object$Foo@73f82f

scala> o.f
line22: java.lang.String = hoge

scala> o.f(1)
line23: scala.Int = 11

↑こんなことはできるが…

scala> class Bar { def f(n:Int) = n + 10; val f = (s:String) => s }
defined class Bar

scala> val o = new Bar
o: line31$object.Bar = line31$object$Bar@13c72d

scala> o.f(1)
line33: scala.Int = 11

scala> o.f("hoge")
<console>:5 error: type mismatch;
 found   : java.lang.String(hoge)
 required: scala.Int
  val line34 = o.f("hoge")
                   ^

scala> val vf = o.f
vf: (java.lang.String) => java.lang.String = <function>

scala> vf("hoge")
line36: java.lang.String = hoge

このように、オーバーロードはしてくれない。

その三
どっちもオーバーライドはできる
scala> class Base { val a = "base"; def f(s:String) = Console.println(s) }
defined class Base

scala> class Sub1 extends Base { override def f(s:String) = Console.println("Sub1"+s) }
defined class Sub1

scala> class Sub2 extends Base { override val a = "sub2" }
defined class Sub2

scala> new Sub1 f("hoge")
Sub1hoge
line46: scala.Unit = ()

scala> new Sub2 a
line47: java.lang.String = sub2

ところで上記のように、例の空白区切り記法を使うと new したオブジェクトにそのままメッセージを送れたりして、ちょっぴりナイス。 ドット記法だと…

scala> new Sub1.f("hoge")
<console>:4 error: not found: value Sub1
  val line49 = new Sub1.f("hoge")
                   ^

scala> (new Sub1).f("hoge")
Sub1hoge
line50: scala.Unit = ()

こんな風にカッコを使わないといけない。 まあこっちの方が普通だけど(苦笑

% [Scala] クラスのコンストラクタ

なんかちょっとクセがある。

scala> class InitTest { def this(s:String) = { this(); Console.println(s) } }
defined class InitTest

こんな感じで this という名前のメソッドを定義すると、それがコンストラクタになるんだけど、例えばこんな風にすると…

scala> class InitTest { def this(s:String) = { Console.println(s) } }
<console>:2 error: 'this' expected but identifier found.
class InitTest { def this(s:String) = { Console.println(s) } }
                                        ^
<console>:2 error: '(' expected but '}' found.
class InitTest { def this(s:String) = { Console.println(s) } }
                                                           ^

…エラーになる。 要するに、まず必ず別のコンストラクタを呼ばなきゃならない。 それってどこの Objective-C ? よーし [self init] しちゃうぞ(謎

さて、別のコンストラクタを呼ばなきゃならないということは、少なくともコンストラクタを定義しようと思ったら最初から存在する this() を呼ばなくちゃならない。 と言うことはぶっちゃけ『引数無しのコンストラクタは自分じゃ定義できない』ということになる。 まあ、val の中身は new されたときに評価されるんで、そこら辺でごにょごにょすれば何とかなるのかも知れないが。

% [雑談][Scala] 眠い……

うー、type bounds のことを調べたかったんだが、今日はもうダメだ。ツラい。 また明日。


2006-04-12 [長年日記]

% [PC][雑談] 今日の無駄遣い

何となく無駄遣いしたい気分だったので、キーボードとかを勘で買ってみた。勘で!!

ものは ELECOM の TK-UP87MP というもの。 『ノートパソコンと同じキータッチ』とか書いてあって、「なんのこっちゃ?」と思ったらパンタグラフ方式なんだって。 ぶっちゃけそんなんはどうでも良いわ。

ともあれ、ノートパソコンを引き合いに出すってことは、わしの好きなストロークが浅めのやつだろうってことで値段も手頃だしゲット。 ほんとは英語配列が欲しかったんだけど、最近は Mac で日本語配列を英語配列にごまかして使うのも簡単になったんでがまんする。 どうせ刻印なんて見ないし。

んで、使ってみた感じ……まあ、値段相応。 まだあたりが付いてないせいか、押したつもりが押ささってないっていうことがたまにあるが、この辺は慣れでなんとかなるだろう。 底板もわりとしっかりしてるんでキータッチは及第点だが、キーがカチャカチャうるさいな。 これもあたりが付いてくれば多少マシになりそうではあるが。

ただ個人的に一番困った問題はケーブルが出てる場所だな。 リンク先の写真を見ればわかると思うが、右側面から出てるんである。 そこにあると激しく邪魔。 だってそこにはトラックボール様が鎮座ましましてる訳だからね、わしの場合。 仕方なく、今まで付けていたパームレストを取り外して、トラックボール自体を手前に持ってくる事でコードとぶつからないように調整した。 でもキーボードとトラックボールの位置関係が今までと違っちゃうから、慣れるまでしんどい……

使わない時に立てておけるってのがウリの一つみたいだから、コードが横から出てる事は仕方ないと思うけど、そこでなぜ右からかなー。 もしかしてこれ、左利き用キーボードなのか? マウス使ってる人だって、ここにコードが伸びてると邪魔だと思うんだが。 理想を言えば、右でも左でもどっちにも出せるような仕組みが望ましいけど、4,000 円のキーボードにそれを望むのは酷かなあ。

ともあれ、

  • キーボードに高い金は出したくない。
  • でも PC 買うと付いてくるテンキー付きのドデカイやつは邪魔い。
  • かと言って、キーピッチはフルサイズじゃないとイヤ。
  • ファンクションキーは必要だよね?
  • Enter キーがでかいと興奮する。
  • パンタグラフと聞くと血が騒ぐ。

という嗜好の人にはそれなりにお薦めできそうな一品であった。 しばらく使い続けてみよう。

% [Scala] Upper Type Bounds

うーん、よくわからん。 一種の type annotation みたいだけど、これがあることによるメリットがさっぱり。

うんうん唸って考えたが、結局使い道ってこういうことか?

scala> class A { }
defined class A

scala> class B extends A { }
defined class B

scala> class C extends A { }
defined class C

scala> def f[T <: A](obj:T) = Console.println(obj);
f: [T <: line0$object.A](T)scala.Unit

scala> f[B](new B)
line1$object$B@fcb00e
line4: scala.Unit = ()

scala> f[B](new C)
<console>:7 error: type mismatch;
 found   : line2$object.C
 required: line1$object.B
  val line5 = f[B](new C)
                   ^

scala> f[Int](new A)
<console>:6 error: type arguments [scala.Int] do not conform to
                   method f's type parameter bounds [T <: line0$object.A]
  val line6 = f[Int](new A)
               ^
<console>:6 error: type mismatch;
 found   : line0$object.A
 required: scala.Int
  val line6 = f[Int](new A)
                     ^

これがどれだけ嬉しいかはピンと来ない。 確かに Generics を使う際の型検査が堅固になるだろうとは思うが。 端的に言うと、Generics のパラメータを特定の型のサブクラスのみに制限するということ……なんだよね?

ところでここページのサンプルコード見てると、わりかし重要そうなメソッドが判明するね。 isInstanceOf と asInstanceOf ってやつ。 isInstanceOf は型検査 (Java の instanceof) で、asInstanceOf はキャストみたいだ。

% [Scala] Lower Type bounds

これもよくわからん。 でもがんばって考えてみる。 こんな感じかなあ。

// class A B C は上記を流用
scala> class D extends B { }
defined class D

scala> def foo[T >: B](arg:T) = Console.println("foo");
foo: [T >: line1$object.B](T)scala.Unit

scala> foo[B](new B)
foo
line16: scala.Unit = ()

scala> foo[A](new A)
foo
line17: scala.Unit = ()

scala> foo[D](new D)
<console>:6 error: type arguments [line10$object.D] do not conform to method foo's type parameter bounds [T >: line1$object.B]
  val line18 = foo[D](new D)
                  ^

要するに、Upper Type Bounds の逆をやってるだけだけど。 つまり、Generics のパラメータを特定の型のスーパークラスに制限している。

Upper にしても Lower にしても、有効に使いこなすにはセンスがいりそうだなあ。 わしは自信無い(トホホ

% [雑談] もろもろ

うーん、例のキーボードはどうも思ったほどにはストロークが浅くないので、今まで使ってたキーボード (こいつは浅め) の感覚で打ってると打ち漏らしが出るなあ。 慣れるまで気持ち悪いぞ、これは。

今日は FSS の 12 巻を買ってきたんで、これから読む。 気を抜くと 1 巻から読みふけってしまうから気を付けよう(苦笑)。 つーか、そんなことしたら丸一日つぶれるけどな。

それにしても、最新刊が出たからって VIP でスレが立ったり、みんな大騒ぎしすぎ。 ……いやまあね、20 年かけてやっとこ 12 巻だっつーのもどうかと思うけどね。 絶対完結しないよな。

% [Scala][ツッコミ] soutaro さんからのツッコミその1

脳の出来の問題でなかなかスパッといかないので、一つずつ。 まずは、

>Upper Type Bounds

TをAのサブクラスに制限することによって、Aのメソッドが呼べるようになる、ということだと思います。

から。

ふむふむ、つまりどういうことかしら? とりあえず思いつくままやってみましょう。

scala> class A { def f() = Console.println("A") }
defined class A

scala> class B extends A { override def f() = Console.println("B") }
defined class B

scala> def g[T](o:T) = o.f();
<console>:4 error: value f is not a member of T
  def g[T](o:T) = o.f();
                   ^

あ、これですか? この制限を避けつつ、Generics の恩恵も受けられるようにするのが Upper Type Bounds の役目ってことですかね。 なんとなく納得。

% [Scala][ツッコミ] soutaro さんからのツッコミその2

次行ってみましょう。

>Lower Type Bounds

型パラメータが関数の返り値の型になるとどうでしょう?

ふむ、もう一度考えてみますよ。

scala> def create[T]():T = new T;
<console>:4 error: value this is not a member of T
  def create[T]():T = new T;
                      ^

scala> def create[T>:B]():T = new B;
create: [T >: line1$object.B]()T

scala> create[A]()
line28: line0$object.A = line1$object$B@623389

あー……

さらに、例題を自分で追試してみるテスト。 ただしちょっぴり手抜きして簡素化。

scala> class Cons[T](head:T, tail:Cons[T]) { def prepend(e:T):Cons[T] = new Cons(e,this); }
defined class Cons

うむ。 ・・・空リストはどうやって作るの? これって OCaml で variant を使わずにハマっちゃったりするパターンに似てるなあ。

そこで次に、まだよくわかってない covariant annotation の登場ですか。

scala> class Cons[+T](head:T, tail:Cons[T]) { def prepend(e:T):Cons[T] = new Cons(e,this); }
<console>:5 error: covariant type T occurs in contravariant position in type T of value e
  class Cons[+T](head:T, tail:Cons[T]) { def prepend(e:T):Cons[T] = new Cons(e,this); }
                                                     ^

よくわかんないけど、+T というのは covariant な T を表してるらしくて、この場合、e のところで contravariant になる可能性があるからダメよ……と言ってるんですね? ごめんなさい、わけわかりません。 って言うか、covariant とか contravariant がどんなものを指してるのかわかってませんが。

Variances のページとか見ながら想像すると、T が常にそれよりも親側のクラスである状態を covariant って呼んでるんでしょうか。 上のようなシチュエーションだと、例えば Cons[A] のインスタンスでも e に対して A の子クラスである B のインスタンスも使えてしまうから、制限に引っかかると。

そうすると、逆に子側のクラスに限定するのが contravariant なんですかね? まあ、この話は置いときましょう。よくわかんないんで(苦笑

それで、ここで Lower Type Bounds を使うと…

scala> class Cons[+T](head:T, tail:Cons[T]) { def prepend[U>:T](e:U):Cons[U] = new Cons(e,this); }
defined class Cons

U は T のスーパークラスかもしくは同じクラスであることが保証されるので、+T という条件を満たすことができる……みたいな感じなのかな?

本日のツッコミ(全3件) [ツッコミを入れる]

% soutaro [>Upper Type Bounds TをAのサブクラスに制限することによって、Aのメソッドが呼べるようになる、とい..]

% soutaro [すみません、Scalaがよくわかってないうえに、型の話そのものもなんか混乱してきちゃいました…orz ちょっと考えて..]

% TrackBack [http://jijixi.azito.com/cgi-bin/diary/index.rb?date=200604..]


2006-04-13 [長年日記]

% [Mac][Java] エラーメッセージの文字コード

なんでデフォルトが Shift_JIS なんだよ。せめて UTF-8 にしとけ。 なんか以前は LANG=C にしてやれば英語でエラーを出してくれたような記憶があるんだけど、現在は LANG が何だろうが問答無用で日本語でエラーを出すんで SJIS じゃない端末だと文字化けしまくり。 つーか、どこの世界に SJIS で端末表示してるやつがいるというのか。

と言うわけで、以前にも調べたんだけど忘れちゃったんでもう一度調査した。 んで、ググってググって解決策判明→参考:Q: Mac OS X 10.1でProject Builderを使うと、Javaコンパイラのエラーメッセージが文字化けします。どうしてでしょうか?

要するに javac とかに↓みたいなコマンドオプションを与えるべし。

% javac -J-Dfile.encoding=EUCJP Hoge.java
% javac -J-Dfile.encoding=UTF8 Hoge.java

% [Scala] Scala から Java のクラスをいじる練習

練習つっても基本的には普通に使えるっぽいんだけど。

scala> import java.util._
import java.util._
scala> val al = new ArrayList
al: java.util.ArrayList = []

scala> al.add(1)
line8: scala.Boolean = true

scala> al.add(2)
line9: scala.Boolean = true

scala> al.add(3)
line10: scala.Boolean = true

scala> for (val i <- al.iterator; i.hasNext) yield Console.println(i.next)
<console>:7 error: value filter is not a member of java.util.Iterator
  val line11 = for (val i <- al.iterator; i.hasNext) yield Console.println(i.next)
                    ^

うぐ……

scala> def iter(i:Iterator):Unit = if (i.hasNext) { Console.println(i.next); iter(i) } else ();
iter: (java.util.Iterator)scala.Unit

scala> iter(al.iterator)
1
2
3
line20: scala.Unit = ()

こんな感じか。

Generics には互換性が無いみたいで、

scala> val l = new ArrayList[Int]
<console>:6 error: java.util.ArrayList does not take type parameters
  val l = new ArrayList[Int]
              ^

こういうのはできないみたいだけど、どのみちちゃんとするなら Java 側のクラスをそのまま生でいじるなんて止めた方が良いので、適当に Scala 側のクラスでごにょごにょやってやれば良いんじゃないかと思われる。

……ここで試しに ArrayList のための委譲クラスを書いてみようと思ったが、単純作業みたいな気がしたからめんどくさくて止めた。 そういや委譲が言語仕様に組み込まれてる JVM で動く言語があったなあ。 最近はどうしてるんだろう?→関連項目?

% [Scala][Java] Java から Scala をいじる練習

非常に簡単。

% cat Test.scala
class Test {
   def print() = Console.println("output from scala.");
}
% cat ScalaTest.java
public class ScalaTest {
   public static void main(String[] args) {
      Test o = new Test();
      o.print();
   }
}
% scalac Test.scala
% javac -cp "~/mylocal/share/scala/lib/scala-lib.jar:." ScalaTest.java
% scala ScalaTest
output from scala.

scala コマンドは、中身を見てみればわかるけど単に必要なオプションを付加して java コマンドを呼ぶだけのシェルスクリプト。 だからオプションを把握できてれば、scala コマンドじゃなく java コマンドを使ったって良い(はず)。

本日のツッコミ(全2件) [ツッコミを入れる]

% みずしま [> そういや委譲が言語仕様に組み込まれてる JVM で動く言語があったなあ。最近はどうしてるんだろう? 作者です(..]

% jijixi [おお、これはわざわざどうも。 期待してますんで、がんばってください。 と言っても、プレッシャーかけてるわけじゃないの..]


2006-04-14 [長年日記]

% [Scala] subtype / covariant / contravariant (soutaroにっき)

お、解説してもらってすいません。 なんとなくわかった気がしてきました。

でも、文章にまとめてみようとしたら失敗したので、たぶんちゃんとわかってません(苦笑

% [Scala] ↑の続き

修正しましたので、もう一度見ていただけると嬉しいです。

とのことで、見てみました。 ふむふむ。 うーんと…続く。

% [Scala] variance annotations

covariant と contravariant が何を意味してるかが何となくわかったので、再度このページの内容を考えてみる事に。 簡潔に言って、

covariant とは
型 B が型 A のサブタイプなら、Hoge[B] は Hoge[A] のサブタイプである…ということ

…なんだろう。 つまり Hoge[+T] というクラスを定義したなら、Hoge[B] は Hoge[A] のサブタイプとして扱える。 試してみよう。

scala> class A {}
defined class A

scala> class B extends A {}
defined class B

B は A のサブタイプ (サブクラス) である。 ここで covariant だと指示しないクラスを定義してみる。

scala> class Hoge[T] {}
defined class Hoge

scala> val o:Hoge[A] = new Hoge[B]
<console>:7 error: type mismatch;
 found   : line21$object.Hoge[line20$object.B]
 required: line21$object.Hoge[line19$object.A]
  val o:Hoge[A] = new Hoge[B]
                  ^

こんな感じ。 んで、covariant だと指示してやると…

scala> class Hoge[+T] {}
defined class Hoge

scala> val o:Hoge[A] = new Hoge[B]
o: line23$object.Hoge[line19$object.A] = line23$object$Hoge@363c50

こうなる。 ふむ、これは理解できた。 逆に contravariant の場合はどうだろう。

scala> class Fuga[-T] {}
defined class Fuga

scala> val o:Fuga[A] = new Fuga[B]
<console>:7 error: type mismatch;
 found   : line25$object.Fuga[line20$object.B]
 required: line25$object.Fuga[line19$object.A]
  val o:Fuga[A] = new Fuga[B]
                  ^

scala> val o:Fuga[B] = new Fuga[A]
o: line25$object.Fuga[line20$object.B] = line25$object$Fuga@34fc1a

関係が逆転している。 うん、なるほど。 わかったよ。 でもね、でも……例の

scala> class Cons[+T](head:T, tail:Cons[T]) { def prepend(e:T):Cons[T] = new Cons(e,this); }
<console>:5 error: covariant type T occurs in contravariant position in type T of value e
  class Cons[+T](head:T, tail:Cons[T]) { def prepend(e:T):Cons[T] = new Cons(e,this); }
                                                     ^

これがエラーになる理由がイマイチわかんない。 問題を単純化するために、もう少し簡単で同じエラーが出る例を考える。

scala> class Foo[+T] { def f(e:T) = Console.println(e) }
<console>:4 error: covariant type T occurs in contravariant position in type T of value e
  class Foo[+T] { def f(e:T) = Console.println(e) }
                        ^

どうやら f の返り値なんかは関係無いようだ。 とすれば何が問題なのか?

soutaro さんの説明をよーく読むとヒントがあった。

X = A -> BとY = A' -> B'という型X,Yがあったとき、X <: Yとなるのは、A' <: AかつB <: B'が成り立っているときです。

とある。 これに倣うと上の例は……

  • Foo[B] が Foo[A] のサブタイプであるなら
  • そのメソッドである Foo[B]#f は Foo[A]#f のサブタイプでなくてはならず
  • そのためには A は B のサブタイプでなくてはならない
  • これは Foo[B] が Foo[A] のサブタイプであるための条件に矛盾するので上記の例はエラーになる

ということかな? そして Lower Type Bounds を使って次のようにすれば…

scala> class Foo[+T] { def f[U>:T](e:U) = Console.println(e) }
defined class Foo

e が T のスーパータイプ (スーパークラス) であることが保証されるので、Foo[B]#f が Foo[A]#f のサブタイプであることになり、Foo[+T] の条件を満たす事ができる。 こんな感じだろうか。 せっかくだから反対の例も作ってみよう。

scala> class Bar[-T] { def f[U>:T](e:T) = Console.println(e) }
<console>:4 error: contravariant type T occurs in covariant position in type >: T <: scala.Any of type U
  class Bar[-T] { def f[U>:T](e:T) = Console.println(e) }
                         ^

scala> class Bar[-T] { def f[U<:T](e:U):T = e }
<console>:4 error: contravariant type T occurs in covariant position in type [U <: T](U)T of method f
  class Bar[-T] { def f[U<:T](e:U):T = e }
                  ^

いかにも『作ってます』感満点だけど(苦笑

本日のツッコミ(全2件) [ツッコミを入れる]

% soutaro [最初のやつは、ウソばっかりでぐだぐだでした…orz 修正しましたので、もう一度見ていただけると嬉しいです。]

% TrackBack [http://jijixi.azito.com/cgi-bin/diary/index.rb?date=200707..]


2006-04-15 [長年日記]

% [OCaml] Camlp4 チュートリアル

ぬおぉ……リファラ巡りしてたら偶然見つけた。 こっそりこんなものを作ってるなんて、ひどいや向井さん(どう見ても八つ当たりです)。

今年こそは Camlp4 を憶えようと心に決めて早四ヶ月。 ……何にも進んでねえ(倒

よし、これを足がかりに今度こそ何とか……

実のところ OCaml を憶えたての頃から、Camlp4 は憶えたいって思ってるんだけど、いまだにさっぱりなのはどうかと思う...orz

いや、なんつーの? Camlp4 のソースって見てて目がチカチカするじゃない。 "<" とか ">" とか多すぎ!!みたいな。 カッコ満載の S 式なんかもアレだけど、それ以上に目に刺さる感じがするよね。 とんがってるし(笑

% [PC] 今日の新言語『Nemerle

via reddit.

CLS (.NET Framework) で動く静的型付けで関数型でオブジェクト指向な言語…らしい。 目指すところとしては Scala と似たようなもんなのかな。 ただ、

Semantically Nemerle is mostly a C# superset.

てのが微妙。 いや、わし C# っていじった事無いんだけど、基本的な文法って C++ の亜種でしょ?

ともあれ Tutorial を流し読み。 OCaml の let に相当するのが def か。 んで、def の代わりに mutable を使うと変数になる。

それにしてもなんだろう、この何となく感じる微妙さ加減は……あー行末のセミコロンのせいか。 こんなのもうやめれば良いのになあ。

型推論は Scala より賢いように見える。

def f (x) {
  x.Length
};

こんな関数書けるみたいだし。 ただ、これって x の型は OCaml で言うところの < Length : 'a; .. > as 'b みたいのじゃなくて、'_b なのかなあ。

……結局試してみないと気が済まないわし。 Mono でも動くみたいなんで、サクッとインストールしてみた。

% ledit nemish
Welcome to Nemerle interpreter (using ncc 0.9.1.0).

Please enter expressions appended with ";;".
Type "Help;;" for more info.

Please wait while evaluating the config file..

普通に動くみたいだ。

- def a = "hoge";;
def it : void

ふむ。

- def f (x) {
=   x.Length
= };;
Object reference not set to an instance of an objectin <0x0004c> Nemerle.Compiler.MainParser:peek_sibling_token ()
(以下略)

ぐへ。

- def f (x) {
=   x.Length
= };
= f ("foo");;
: error: there is no member named `Length' in System.Object with type System.Object+

はて?

- def f (x:System.String) {
=   x.Length
= };
= f ("foo");;
def f : System.String -> System.Int32
def it = 3 : System.Int32

うーん、これじゃ意味無い。 対話環境だとこの辺の型推論してくれないってことなのかな。 どっちにしても、関数 f は多相型ではないみたいだけど。

話は変わって Parametric polymorphism について。

The ML-lovers would rather write 'a instead and read it alpha (it is a convention to use identifiers starting with an apostrophe for type parameters). They are allowed to do so, as the apostrophe is allowed in identifiers in Nemerle. We will however stick to a C++-like convention.

わはは。 別に ML-lovers な人たちにお愛想しなくったって良いのに。

ともあれ、いろいろ試してみたい気はするけど、ざっと見た感じ Scala の方がおもしろそうだし、対話環境が激しく役に立たない (ちょっと変な入力しただけでいちいちバックトレース吐くなよ) ので、とりあえずこの辺で止めとく。

% [Nemerle] Macros

本艦はこれよりトランスフォーメーションに……(違

うーむ、これがウリなのかな。 残念ながら不得意分野(苦笑

マクロ大好きな人は Scala より Nemerle に行った方が良い…とそんな感じですか。 プラットフォームの良し悪しはわしにはわからんが、Windows 以外でなら今のところは JVM の方が安心感があると思われる。

言語そのものなら多分 Scala の方がわしの好み。 と言うか、Scala の方がより関数型言語っぽい。 だってカリー化は?とか。 いちいち説明に ML を引き合いに出すわりには Nemerle にはカリー化が無いっぽいし、きっと部分適用はマクロで何とかするんだぜ。 Lisp じゃん。

・・・何言いたいのかわかんなくなった。

ところで『Nemerle』って何て読むんだろう。 『ねまーる』『にまーる』…うーん。

% [雑談] アイフル「上目づかい」「鳴く」非情な取り立て実態明らかに (bogusnews)

これはひどい。 こんな取り立て方されたら抗えないぢゃないか(笑

本日のツッコミ(全2件) [ツッコミを入れる]

% みずしま [> うーん、これじゃ意味無い。対話環境だとこの辺の型推論してくれないってことなのかな。どっちにしても、関数 f は多..]

% jijixi [なるほど、通常のメソッドは型もきちんと書けってことなんですね。 なんでそんな制限があるのかわかりませんけど。]


2006-04-16 [長年日記]

% [Nemerle] Quick Guide

こういうページがあると楽だなあ。


2006-04-18 [長年日記]

% [PC][雑談] f (f x) --> -x

今大変話題。

向井さんと同じの思いついたんだけど、テストする前にダメなのを暴露されてしまったので、ネタに走ろうと思ったらそれも先に lethevert さんにやられててガックリ(苦笑

でもせっかくだからネタ展開。 lethevert さんのは Scheme に慣れた人じゃないと、何やってるかわかりづらいと思うので、わしは誰にでもわかる Ruby で書く。

irb(main):023:0> [0,0.5,1,1.5,2,2.5].each do |x|
irb(main):024:1*   p "#{x} ==> #{f(f(x))}"
irb(main):025:1>   p "#{-x} ==> #{f(f(-x))}"
irb(main):026:1> end
"0 ==> 0"
"0 ==> 0"
"0.5 ==> -0.5"
"-0.5 ==> 0.5"
"1 ==> -1"
"-1 ==> 1"
"1.5 ==> -1.5"
"-1.5 ==> 1.5"
"2 ==> -2"
"-2 ==> 2"
"2.5 ==> -2.5"
"-2.5 ==> 2.5"
=> [0, 0.5, 1, 1.5, 2, 2.5]

うん、もちろん f の中身はこう(笑

irb(main):001:0> def f(x)
irb(main):002:1>   if $evil == x
irb(main):003:2>     -x
irb(main):004:2>   else
irb(main):005:2*     $evil = x
irb(main):006:2>   end
irb(main):007:1> end

ホンマごめんなさい。

% [雑談][tDiary] Wiki 記法のワナ

上記の記事は『今日の一行』のタイトルが一部改変されているのである。 本来は f (f x) = => -x というタイトルなんだが、それが --> になってんのね。

なんでかって言うと、Wiki スタイルだと イコール二つは取り消し線の指示なんだな、これが。 そのせいで、忘れて無意識に書いてしまうと、謎のパースエラーに悩まされる(苦笑

一応、本文中だと = と = の間に改行入れてやる事で何とかなったりするんだけど、セクションタイトルだとその技が効かんのであるよ。 改行までがセクションだから。

はー、バッドノウハウ、バッドノウハウ。

% [雑談] 例の問題のコメント欄で出てた Scheme による解

これはなかなかクールないんちきだ(笑

(define-syntax f
  (syntax-rules (f)
      ((_ (f x)) (- x))
          ((_ x) x)))

まあ、これだと

(let ((x (f 0.5)))
     (f x))

とか書かれたらショボ〜ンなんだけど(苦笑

% [雑談][PC] 例の問題のちゃんとした答

ネタ解答ばっか紹介するのもあれなんで、ちゃんとした解にもリンクしとく。

概念的なものは『ヒビルテ』や『d.y.d.』など。 具体的なコードなら『[鍋]鍋あり谷あり』や問題のページのコメント欄の osiire さんの答えとか。

結局ぶっちゃけて言って、いかにうまいこと二つの集合に分けるかってのが肝だったと思うんだけども、偶数奇数で分けるのは思いつかなかった。 才能ナス...orz


2006-04-19 [長年日記]

% [game] バイオハザード4

今さらだけど買ってきた。GC 版。 さっそく始めてみる。

……やべ、これ酔う。

わしにとってバイオシリーズは終わったな。あかんでこれは。 最後までやれるだろうか。 4になって大きく操作系が変わったってのは知ってたけど、実際にどんなのか見てから買うかどうか判断すべきだったなあ (と言っても、今さらそんなの不可能に近いが)。

どう見ても自分の身体が邪魔で見づらい FPS です。 本当にありがとうございました。

こんなシステムなのに、平行移動もできないから方向転換を多用することになって余計に酔うんだよ、くそったれ...orz

% [game] バイオ4日記、マジでバイオシリーズはもうイイや編

わしは別にガンアクションがやりたくてバイオを買ってるわけじゃないんだけどな。 横っ飛びもできない操作体系のくせに、敵はオノやらダイナマイトやらガンガン投げてくるし、どうしろと? 敵を撃つのに自分でポインティングしなきゃないって、それってもうバイオじゃないよねぇ。

くそぅ、こんなにも期待に反するゲームだとは思わなかったよ。 酔うの我慢してまでやる気にならねえ...orz

操作の不自由さだけは元のままで (つーか改悪されてるぞ) 敵の攻撃は激しいなんてどういう拷問だよ。

% [OCaml][Haskell] 関数型言語マニアのための論文紹介(番外速報):MLモジュールでType Classプログラミング (sumiiの日記)

な、なんだってー!! 似たような事考える人はいるんだなあ(苦笑

ちょっとだけ PDF を見てみたけど、あかんわ、わしのような素人にはちんぷんかんぷん。 たぶん、基本的なところは似たようなもんだと思うんだけど、当然わしのようなやっつけ仕事じゃなく、ちゃんと細かいところまで考えてるって感じ?

暇な時にでも、もう少しじっくり読んでみたいところ。

% [雑談][OCaml][Haskell] ↑の何がスゴイって…

日付がスゴイ。わしが例のネタ書いた日と同じ。どんなシンクロニシティですか(笑

いや、むしろわしの日記を読んで「やべ、先越された」って慌ててドラフト出したんじゃないかと(ねーよw

% [PC][雑談] 二回適用すると符号が反転する関数 ([鍋]鍋あり谷あり)

インチキキター!!

def f(x)
  x.tainted? ? -x : ( x.taint; x )
end

この発想は無かったわw (2ちゃん的賞賛)。 bit 演算する方法はチラッとだけ考えたけど、コード考えるのがめんどくさかったんで放置してたっす。 思えばわし、最初の案で挫折してからはインチキしか考えてないや(笑

% [game] バイオ4日記、今までに無い敵登場編

文句を言いつつ、せっかく買ったんだしと、やり続けてしまう貧乏性のわし。 ともあれ、バイオシリーズがどうのこうのって話は忘れて別物と認識すれば、まあ普通に遊べるゲームではあるのかも知れない。 酔いにも慣れてきた (完全に平気ではないけど)。

んで、新機軸の敵キャラが出てきて、うわー。 人間の頭がボンってはじけたと思ったら、なんかタコかなんかみたいなぶよぶよしたものが頭の代わりに乗っかった変な人間誕生。 なんか伸びたり縮んだり、伸ばした触手を振り回したりします。 ・・・えーと。

どう見ても寄生獣です。本当にありがとうございました。


2006-04-20 [長年日記]

% [雑談] 教授に多い名前 (ワラタ2ッキ)

ダメだ、これからもう何を見ても『大助』『教授』に見える気がする(笑

% [game] バイオ4日記、ウイルスの話は終わってたらしい編

あーそー。アンブレラ関係はコードベロニカで決着が着いてるってことですか。 少なくともアンブレラは壊滅してるらしいね。 まあ、ウェスカーのいる組織はまだ存在するから、そこで T とか G とかの研究が続いてたりするのかも知れないが、ともかく今回の話にはあまり関係無いみたい。

んで、今回の生物災害の原因はウイルスじゃなくて寄生虫なんだそうで。 完全に乗っ取られた人間は、もうどっからどう見ても寄生獣。 さらに目が見えない鉄仮面の敵がいるんだけど、そいつは本体が背中にくっ付いててエシディシ様〜みたいなね。 もう、いろいろどっかで見たようなネタ満載で、この系統の草分けであるバイオシリーズがそんなことで良いのか?とかツッコみたいわけだけど。

ちなみに主人公もすでに寄生虫のキャリアになってしまってるので、おそらく最終的には脳を乗っ取れずに右腕だけ乗っ取った寄生虫が活躍する予定 (いくらなんでもそれは無い)。

% [PC][雑談] 今日の新言語『BF-BASIC'n

今さらだけど、日付に注意。 べーしっ君テラナツカシス。


2006-04-21 [長年日記]

% [game] バイオ4日記、やっぱり最後はロケットランチャー編

お約束。 てなわけで、クリア。 まあ、おもしろかったです。求めてたものとは違ったけど。 あと、エイダはエロすぎ(笑

なんちゅーか、ホラーの要素はめっきり薄れて、アクション重視なものになってしまったのは残念だ。 例えればハリウッド映画みたいな感じ。ぶっちゃけ大味。 アクション部分はそれなりにおもしろいけど、ストーリーだとか謎解きだとか怖さだとか、そういう今までのバイオで楽しんでいた要素が薄すぎてにんともかんとも。

映画化されたりしたのが良くなかったのかなあ。 あれのせいであーゆーノリを期待されてしまって、こうならざるを得なかったとか。 サイレントヒルとか零とかは、ちゃんとホラーとしてシリーズを重ねてるけど、元々それらにインスパイアしてたバイオハザードはそういう世界から脱却か。せつないな。

やっぱ、コードベロニカは良かったなあ。 いろんな要素がとても良くバランス取れてた。 そういや、バイオ0はアイテムのシステムがかったるくて、一回しかやらなかったなあ。 久しぶりにやり直してみるかな。


2006-04-23 [長年日記]

% [game] バイオ4日記、そりゃないよ編

あー、何もやる気がせん。そんな感じで惰性でバイオ4。

イージーレベルでクリアして十分満足してたんだけど、ふと攻略サイトとか覗いてみたらイージーだとマップの一部が省略されてたりするってのが判明して激しく鬱。 たしかに、きっちりモデリングされてるわりに絶対入っていけない場所とかがあって、何だろうなとは思ってたんだけどさ。 そりゃないよなー。

もうこうなっちゃうと気になって仕方ないんでノーマルモードで開始。 つ、つれーー。 クリアできんのかな……

一回クリアしてるからまだマシだけど、最初からノーマルでやってたら途中で投げ出してたね、これは。 つーか、そうじゃなくても投げ出しそうな気もするんだが。

% [game] スパロボ OG

今年の PS2 用のスパロボは ORIGINAL GENERATION かあ。 てことは新作は無しね。 んで、これが出た三ヶ月後くらいに GBA で OG3 とかか?

どうでも良いけど、PSP で IMPACT をお手軽にしたバージョンとか出してくれないかなあ。 いや、それよりも F のお手軽版の方が良いかな。 最近の PS2 をフルに使いこなしちゃってるシリーズを PSP に無理に移植しても、ロード長過ぎたりかったるいだけだから、もっと軽いバージョンを移植しようよ。 まあ、できれば新作の方が良いけども。


2006-04-24 [長年日記]

% [Mac] ひさしぶりに AquaSKK を入れてみた

しばらく見ないうちに、随分あか抜けたなあ。

以前は設定項目には存在するけどうまく動いてくれなかった skkserv モードが使えるようになってて、こりゃ幸いと skkinput2 を野良ビルドして使うことにした。

さあ、またしばらく skk 生活だ。


2006-04-25 [長年日記]

% [雑談] 虎視ぎょうぎょう (なぜか変換できない) (ワラタ2ッキ)

『ふいんき (なぜか変換できない)』ってのは、まだ何かわかる気がするけどさ、これは無いだろ(笑


2006-04-26 [長年日記]

% [本日のリンク元] google 検索 (ラシーン -セラシーン -パンチラシーン 2005)

ラシーンのこと調べようとしたら、パンチラばっかりでウンザリしたんだろうな(笑


2006-04-27 [長年日記]

% [game] 街 PSP 版とか

あれー?仕事関係の買い物に行ったはずなのに、なぜかついでにこんなの買ってきてしまってますよ? って言うか、サターン版も PS 版もやったのに、わざわざやる必要無いだろ...orz

……いやね、この手のゲームってやっぱ携帯機にあってると思うわけでね、だからほら。 PSP もしばらく触ってないなーとか思ったらつい……ね。 案の定バッテリー切れてて電源入らなかったしね(苦笑

きっとかまいたち2も買っちゃうんだろうなあ。

あとなんだか、かまいたち3の予定もあるらしいね。 PS2 用みたいだけど。 あと、どういうつもりなのか、2の直接の続編みたい。 何をどう繋げるつもりなんだか (と言いつつ、2の話ももううろ覚えだ…)。

どうせなら最初っから PSP で出してくれりゃ遊びやすいのになあ。 ……それだと数が出ないから駄目か(苦笑

本日のツッコミ(全2件) [ツッコミを入れる]

% Zapper [PS2版でペイしてから、使い回せる部分使い回してPSP版って感じだろうな 分野として通勤時間潰しには向いているから、..]

% jijixi [でも PSP 版はわりとツライわ(苦笑 ただでさえロード時間のせいでテンポ悪いんだけど、たまにロードが無い時間が続い..]


2006-04-28 [長年日記]

% [PC][独り言] 割り込みを使いまくった処理のフローを、もっと素直に書き下す方法って無いもんかなあ……

複数の割り込みが交互に作用しあう場合、マルチスレッドな処理を書くのとほとんど同じな気がするよ。 割り込み処理中に別の割り込みを使いたいときなんか、スレッドと同じ地獄 (排他処理とか) が待ってるし。 かと言って割り込み使わないで書くと、それはそれで面倒だったり。

あー、頭がこんがらがるわい。


2006-04-30 [長年日記]

% [独り言] 今年のゴールデンウィークは……ほぼ無し...orz

部品が入ってくるのが遅れたりとかもろもろの皺寄せが全部こっちにおっ被さってきつつ、納期は一緒みたいなね。 あれ、なんかこういうの聞いたことあるな……ですま?


トップ 最新 追記

日記ってのは本来、自分で読み返すためにあるもんだよなあ……
もしくは有名人になったら死後に本になったりとかか?

RSS はこちら

jijixi at azito.com