2007年 11月 08日

HTML の class

class はまんま OOP のクラスと同じ意味でとらえることができて、

<div class="hentry">
</div>

というのはクラスが hentry である div を表わし、言いかえれば、この div 要素は hentry クラスのインスタンスといえる (hentry に分類される実体)。

二つ以上のクラスのときは多重継承したクラスをイメージすればいいと思いますよ。

モーダルだけいえば

一般的にモーダルなのはよくないことになっていて、とかいいつつメニューとかもモーダルなんだけど、どこでもつかわれているメニューでさえ慣れていない人は操作法がわからないものらしい (おれにはそれがよくわからないけど、例えば MS Office で大量にツールバーアイコンがあるのはそういう人向けらしい)。でもみんな普通にコンピュータ使うときにはモーダルなことをしてる。モードの有無はそれを想像できるならどうでもいいことだと思う。あとはモードの切替えがめんどいかめんどくないかとか、デフォルトのモードが適切かどうかとかぐらいな感じがする。


どこらへんで妥協して線をひくかがいつも重要だけれど、そういうのって頭よくないとできないんだよなぁとつくづく感じる。おれにはできる気がしない。プログラミング言語デザインとかもそうだよなぁ (S式がなんでだめかみたいな。なんかここ最近S式がなんでだめかとか考えてばっかなんだけど)。

Vim の自動補完候補表示

http://screencast.com/t/jfQ2fz8HHL (月あたりの転送量を超えたらしく見れなくなった。Jing は 1G/month らしい)

http://lab.lowreal.net/trac/browser/config/.vimrc#L225

使いはじめてしばらくたったけど、快適すぎる。けっこう重くなるから非力マシンだと使えなそうだけど、頭使わずに補完が使えるようになってほんとに楽だ。noignorecase にしないとあれになるから検索とかが不便になるけど、それを考えてもいいかんじ。

数文字うったら候補が勝手に表示されて、候補がおおかったらずっとうちつづけられるし、候補があったらすぐ TAB 連打して入力できるし……

追記
http://subtech.g.hatena.ne.jp/cho45/20071111/1194766579

http://www.vim.org/scripts/script.php?script_id=1879

っていうのが既にあるよ! オプションとかあるからこっちのほうが便利だよ!

Monad

順序処理を関数の入れ子に、また関数自体の値と平行して副値を走らせることで「副作用」をパッケージ化するというのがモナドのコンセプトである。

http://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%8A%E3%83%89_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)

やっとこの部分が実感できた。やっぱちゃんと書いてみるってのはてっとりばやいなぁ。IO モナド以外はうまくイメージできてないけど……

言語

Haskell の (\x -> a * x) みたいな匿名関数の表記はかなりビビっとくる。なんていうかこう、可愛い女の子を見たときの気持ちにている。腹の底がグっって持ちあがる感じ、わくわくする感じ。

JS でもこんぐらい短いといいのになぁ。というか JS は return かかないと値返さないのがダメすぎる。なんであんな仕様にしたんだろ。もったいない。Lua もだ。最後に評価した式の値返せばたくさん幸せになれるのに……

あと Lua はめっちゃ JS だよ。JS

a = List.new(1, 2, 3)
a:map(function (i)
    return i * i
end)
a = new Array(1, 2, 3);
a.map(function (i) {
    return i * i;
});
2007年 11月 07日

勉強するものじゃない。

なんか

ホットエントリとか、そういうののブクマコメをよんでいて感じる気持ちって、うまく表現できない。俺がいままで思っていたよりも、俺と決定的に合わない人っていうのは、多いんだなぁと、近頃、特にここ三ヶ月ぐらいは、感じる。

Lua で Blosxom クローン

http://coderepos.org/share/browser/lang/lua/bluasxom/bluasxom.lua

ファイル列挙するのが生の Lua でできないので ruby よんで解決。他の部分は Lua だけでかいた。Class と List は前に RO 用に書いたのをそのままつかった。reverse を定義していないことにきづいたけど sort の等号変えてアドホック解決。Lua の文字列リテラルはおもしろくて

[[...]]
[=[ ... ]=]
[==[ ... ]==]
[===[ ... ]===]

みたいに = をふやして入れ子にできる。コメントなんかも複数行書きたいときは -- のあとにコレかくんだけど、これのおかげでテンプレートのコンパイルのときに楽をしてる。それとテンプレートの include (コンパイル時に処理しないといけない) とかも入れこにできるから簡単かも。実装してないし、してもあんま意味がないのだけど……

テンプレートへの値のうけわたしは setfenv (set function environment) でやってる。Lua では文字列の eval をしたいとき、 loadstring で文字列を評価する関数をつくって、それをよぶという感じなので、loadstring のかえす関数に setfenv をよんでやれば環境が変更できる (これは Ruby でいうところの binding を指定して eval してるようなものだけど、環境も Lua ではただのテーブルなのでより柔軟性がある)。

ただ、たんにテンプレートでつかう値だけを入れたテーブルを setfenv すると os.date とか組みこみの関数がテンプレ内からつかえなくて泣けるので、グローバル環境から一段階値をコピーしてからセットしてる。やっぱ環境に直接さわれるのはおもしろい。JS もさわれたらいいのになぁ。

正規表現リテラルが必要なたったひとつの理由

バックスラッシュ二個かくのめんどくさいだろ……常考……

2007年 11月 06日

モナド・モナド・モナド

Haskell が理解できる気がしてこない。諦めたい気分になってくる (実際書いてるコードは理解しなくても書ける範囲でしか書いてない)。いやもちろん誰かに「やれ」なんていわれているわけじゃない。理解できなくてくやしい。lift が全くわからない。「モナドの全て」の説明を読んでもわかった気にさえなれない。頭が悪い。本当に悪い。頭悪いのを実感できる分野は苦手だ。数学とかまさに。Haskell は数学に近い。ただプログラミングということになっているから耐えられる。いややめるかも。頭のいいわるいなんて生まれつきだから、そんなのいまさらどうしよもない。理解できる人には理解できるんだろうなぁ。

IO モナドが副作用を閉じこめているのは (そういう説明がされているから) わかった気になる。それを扱うとき、そのモナドの中で (この表現が正しいかよくわからない。つまり do ブロックの中といいたい) 処理をして、モナドをはずす (この表現が正しいかよくわからない。つまり IO String を <- をつかってなかの String をとりだすといいたい) ことで、副作用を一旦どっかに置いとくことができるようなことはわかった (ほんとに?)。

この do ブロックの中でなにがおこっているのかわかってない。>> で各行が連結されている? >> はなにをする? 連結。連結ってなに。>>= の = がないバージョン。return がなんなのかわかってない。こいつはなにをするんだ。

return は return :: a -> m a すなわち a をとってモナドにくるまれた a をかえす。モナドのインスタンスをつくる。でもこれ引数に値しかわたしてないけど、どのモナドにくるまれるんだ? コンテキストモナド? コンテキストモナドとかてきとうにいったけど、よくわかってない。それが存在するかすらわかってない。

(>>=) :: m a -> (a -> m b) -> m b バインドとかいうらしい。モナドインスタンス m a と関数を一個とって新しいモナドをかえす。わけわかんない。モナドの中の値を処理してまた新しくモナドインスタンスをつくってる。なんでこんなことする必要があるんだろう。計算を合成するってどういう意味だ。Maybe があるなし一緒にして計算を継続できるようになってるのはいいことなのか。合成ってなんなんだ。関数合成と計算の合成って何がちがうんだ。

そういえば関数合成 . と $ のつかいわけもよくわからない。全部 $ でかけるような。合成のほうが気分的にすっきりするだけ?

aaa >>
bbb

aaa >>=
(\x -> bbb)

みたいなときに x には何が入ってるんだ。aaa の返り値か。まてまてモナドはどこいった。もうすこし実用に近いところでみてみよう

import Network.CGI

cgiMain :: CGI CGIResult
cgiMain =
    setHeader "Content-Type" "text/plain" >>=
    \x -> output "Hello"

main :: IO ()
main =  runCGI $ handleErrors cgiMain

もちろん >>= は >> にして \x -> は消しても動く。それはいい。\x には何が入っているんだ。setHeader の返り値のはずだ。

setHeader :: MonadCGI m => String -> String -> m ()

m () ってなんだ。() がなんだかわからない。null ? 空リスト? いやリストは [] だ。こいつはなんだ。Haskell だと print デバッグができない。\x になにが入っているか直接調べることができない。学習のさまたげだ。print デバッグは偉大だ。

この () とかいうやつは :type しても () そのままうちこんでも () のままだ。どこに定義が書いてあるんだ。探しにくい。これだから記号がいやだ。

まぁいいやもっと簡単にしていこう。こんどはちゃんと前の計算の値をつかうモナドだ。よくあるやつになった

main :: IO ()
main =  readFile "Rakefile" >>= (\x -> putStr x)

readFile は IO String をかえす。>>= で x に IO String のなかの String がバインドされる。そして計算が実行される。

実際は putStr 自体が (\x -> fun x) の形になっているからこう書く必要はなく

main :: IO ()
main = readFile "Rakefile" >>= putStr

でいい。putStr をよばずに、関数として >>= 関数にわたしてやっているだけだ。ん? なんか全く普通だ。関数の定義通りの実行されているにすぎない。モナドが見えない。putStr の返り値は IO () だから main の定義ともあっている。これはまったくもってわからないところがない。あれ?

main :: IO ()
main = readFile "Rakefile" >> putStr ""

たしかになにもでない。あたりまえだ。

もう一回 CGI の例を定義とてらしあわせてみるけど、こっちはやっぱりわからない?

class Monad m => MonadCGI m
data CGIT m a
type CGI a = CGIT IO a
runCGI :: MonadIO m => CGIT m CGIResult -> m ()
setHeader :: MonadCGI m => String -> String -> m ()
output :: MonadCGI m => String -> m CGIResult

--

import Network.CGI

cgiMain :: CGI CGIResult
cgiMain =
    setHeader "Content-Type" "text/plain" >>
    output "Hello"

main :: IO ()
main =  runCGI cgiMain

最終的には IO () を runCGI が返すはずだ。だけど runCGI は m () をかえしている。ここでの m は MonadIO だ IO は MonadIO のインスタンス? だとするとここはあってる。runCGI は CGIT m CGIResult を引数にとる。cgiMain は CGI CGIResult をかえしてる。あれ m は? とおもったら CGIT m か。CGI CGIResult は type を展開すると CGIT IO CGIResult になる。うむ CGIT m CGIResult とマッチする。

setHeader は String -> String をとって MonadCGI をかえしてる。すなわちここでは setHeader が MonadCGI の最初のインスタンスをつくっている (たぶんこのインスタンスが setHeader した結果を保持しているんだろう)。そして、output は m CGIResult をかえしている。m は MonadCGI のインスタンスだ。あれ m CGIResult と CGI CGIResult があってなくないか。data 構築子 CGIT は m a と定義されている。m は MonadCGI。ということは m CGIResult になるな。なるほど。

import Network.CGI

-- 1: cgiMain :: CGI CGIResult
-- 2: cgiMain :: CGIT IO CGIResult
-- 3: cgiMain :: MonadCGI m => m CGIResult
cgiMain :: MonadCGI m => m CGIResult
cgiMain =
    setHeader "Content-Type" "text/plain" >>
    output "Hello"

main :: IO ()
main =  runCGI cgiMain

これでもうごく。ちゃんと整合性とれてる。data CGIT m a のよみかたがわかった。data CGIT は m a と一緒ってことだな。たぶん。

とりあえず型のうごきをみていくと >> のところでモナドインスタンスがうけわたされて処理されているっぽいのがなんとなくわかった。前回の計算結果は捨てているけど、背後でうごめくモナドインスタンスは引き継がれている。ベルトコンベアの比喩も若干わかった。文章にするのはわからないところがわかってそれを理解しようとする試みができて偉大だな。

しかしモナドインスタンスがどうやって計算を保持しているかわからないな。モナドによって保持方法が違うのは想像できるけど、実装はどうなっているんだろう。

まぁそれはおいといて、return もすこし理解できた。上ではでてきていないけど、>>= の右側の関数は m a をかえさないといけないわけだ。でも内部処理した結果がただの String だったりしたときは、モナドでつつみなおさないといけない。そのときん return をつかうとそれをつつんで、次にわたせるってことかな? よしやってみよう。

import Network.CGI

cgiMain :: CGI CGIResult
cgiMain =
cgiMain =
    setHeader "Content-Type" "text/plain" >>
    return "hogehoge" >>=
    output

main :: IO ()
main =  runCGI cgiMain

こうすれば return でつつまれて次の関数に連結され、output に hogehoge がわたされるはずだ。うまくいった。うれしい。


とりあえずつかれた。ここまでやるのに時間かけすぎだ。リストモナドがなんでモナドなのか理解していない。lift は理解できそうもない。Haskell は if も case も let も全く理解していない。まだまだだ……

関数合成 .

test :: String
test = "aaa" >>=
      return . toUpper

みたいにかけるのはいいかも

test :: String
test = "aaa" >>=
      \x -> return $ toUpper x

はちょっとださい。


リストもモナドっていうのをたしかめたくて変なコード書いてる。String は Char のリストなのでモナドの演算ができるはず (直接やらないのは String のほうが出力しやすいから) うえのは単に map (\x -> toUpper x) "aaa" と一緒だから良さがよくわからないけど、リストモナドから要素を一個一個とりだして関数適用してるっぽいのはわかったかも。