Template Haskell のお勉強ちう、そのさん - 準クォート

そのいち、そのに、とはあまり関係ないですが、いちおう続きです。quasi-quote とか準クォートとかいうもののお話です。

はいっ、そういうものです。

パーサに渡す文字列は、

[quasiquoter|hogehoge|]

の、ように、通常の Template Haskell と同じようなやつ (Oxford bracket というらしい) で括ります。quasiquoter の部分は、プログラマが好きな名前に決めます。括った文字列は、呼ばれた文法上の位置に応じたパーサに渡され、パーサは Q モナドを返します。ExpQ とか PatQ とか。

Common Lisp のリーダーマクロとか、同じような仕組みなんでしょうか。Common Lisp よく知りません。

様々な DSL を実装するのに使われているようです。よく知りません。

もっとちゃんとした解説を読みたい方は、例によって @mr_konn さんのチュートリアル (準クォートでもてかわゆるふわメタプログラミング! - はてな使ったら負けだと思っている deriving Haskell - haskell) とか読むといいと思います。

このような仕組みですので、Haskell に好きな言語を埋め込めます。そう! 例えば Lazy K とか!

そんなわけで lazyK という QuasiQuoter を作ってみました。これを使うと Hello World がこんな感じです *1

{-# LANGUAGE TemplateHaskell,QuasiQuotes #-}

import LazyKQQ
import Control.Applicative ((<$>))

program =
    [lazyK|
     `k``s``si`k``s`k```sii``s``s`kski``s``s`ksk``s``s`ksk```s``siii``s``s`k
     ski`k``s``si`k``s``s`ksk```s``s`kski``s`k``s``s`kski``s``s`ksk```sii``s
     ``s`kski`k``s``si`k``s`k```sii``s``s`kski```sii``s``s`ksk``s``s`kski`k`
     `s``si`k``s`k```sii``s``s`kski```sii``s``s`ksk``s``s`kski`k``s``si`k``s
     ``s`ksk``s`k``s``s`kski``s``s`ksk``s`k``s``s`kski```sii``s``s`ksk``s``s
     `kski`k``s``si`k````s``s`ksk```s``siii``s``s`kski`s``s`ksk```sii``s``s`
     ksk``s``s`kski`k``s``si`k``s`k``s``s`kski```s``siii``s``s`kski`k``s``si
     `k``s`k``s``s`ksk``s`k``s``s`kski``s``s`ksk``s``s`kski``s``s`ksk```s``s
     iii``s``s`kski`k``s``si`k``s``s`ksk``s`k``s``s`kski``s``s`ksk``s`k``s``
     s`kski```sii``s``s`ksk``s``s`kski`k``s``si`k``s`k``s``s`kski``s``s`ksk`
     `s`k``s``s`kski``s``s`ksk```sii``s``s`ksk``s``s`kski`k``s``si`k``s`k```
     sii``s``s`kski```sii``s``s`ksk``s``s`kski`k``s``si`k```s``s`kski``s`k``
     s``s`kski``s``s`ksk```sii``s``s`kski`k``s``si`k``s``s`ksk``s`k``s``s`ks
     ki```s``siii``s``s`kski`k``s``si`k``s`k``s``s`kski``s``s`ksk```sii``s``
     s`kski`k``s``si`k```sii```sii``s``s`kski`k```sii```sii``s``s`kski
     |]
main = output . eval =<< (program :$) . encode <$> getContents

[lazyK| 〜 |] で括った部分を書き換えると、当然ですが別のプログラムになります。Unlambda インタプリタ *2 とか。 *3

{-# LANGUAGE TemplateHaskell,QuasiQuotes #-}

import LazyKQQ
import Control.Applicative ((<$>))

program =
    [lazyK|
````sii``s``s`ks``s`k`s`ks``s``s`ks``s`kk``s`ks``s`k`s`k``si`kk``s`k`s``s``si`
kk`k``si`k`ki``s`kk``s``s`k``s``s`ks``s`kk``s`k``s``s`ksk``s`k``s``s`kski```s`
`siii``s``s`kski``s``s`ks``s`kk``s`ks``s`k`sik`kk``s`k`s``s`k``s``s`kski``s``s
`ks``s`kk``s`ks``s`k`sik`kk``s``s`ks``s`kk``s`ks``s`k`si``s`kk``s`k`s`k``sii``
s``s`ks``s`k`s`ks``s`k`s`kk``s`k`s`ks`s`k`s``s``s``s``si`kk`k``si`k`ki`k````s`
`s`kski```s``s`ksk```sii``s``s`kski``s`k`s``si`k`kik``s``si`kk`k```sii``s`k``s
`k`s``si`k`kik``sii`kk`k`k``s``s`ks``s`kk``sii`k``si`k`ki``s`k`s`kk``s`k`s``s`
k``s``s`kski``s`k``s``s`ksk```sii``s``s`kski``s``s`ks``s`kk``s`ks``s`k`sik`kk`
`s`k`s`k``s`k`s``si`k``s``s`ks``s``s`ksk`k``s`k`si``s`kk``s`k`s``s`ksk``s`kk``
s`ks``s`kk``s`ks```ss`s``s`ks``s`kk``s`ks``s`k`si```ss`si`kk`kk`k``si`k`kik``s
`k`s``s`k```s``siii``s``s`kski``s``s`ks``s`kk``s`ks``s`k`sik`kk``s`k`s`k``s`k`
s``si`k``s``s`ks``s``s`ksk`k``s`k`si``s`kk``s`k`s``s`ksk``s`kk``s``s`ks``s`k`s
`ks``s`k`s`k`s`ks``s``s`ks``s`kk``s`ks``s`k`s`ks``s`k`s``s`ksk``s`kk``s`k`s`k`
`s`k`sik``s`k`s`k``si`kk``s`k`s``s``si`kk`k``si`k`ki``s`kk``s``s``si`kk`k``s`k
`s``si`kik`k``s``si`k```sii``s`k`s``s`ksk``s`kk``s`k`s`kk``s`k`si``s`kk``sii`k
```sii``s`k``s`k`s``si`kik``sii`k``s`kkk`k`k`ki`k``si`k`kik``s`k`s`k``s`k`s``s
i`k``si`k``si`k``s``s`ksk`k``s``s`ks``s`k`s`ks``s`k`s``s`ks``s``s`ksk`k``s`k`s
i``s`kk``s`k``si`kk``s``s``s``si`k`ki`kk`k``si`k`ki`k`````sii```sii``s``s`kski
``s`k`s``si`kik`k```sii``s`k`s``s`ksk``s`kk``s`k`s`kk``s`k`si``s`kk``sii``s`kk
k`k`k``si`k`kik``s`k`s`k``si`k`ki``s`k`s``s`k``s``s`kski``s`k```s``siii``s``s`
kski``s``s`ks``s`kk``s`ks``s`k`sik`kk``s``s`ks``s`kk``s`ks``s`k`si``s`kk``s``s
`ksk``s``s`ks``s`kk``s`ksk`k``s``s`ks``s`kk``s`ksk`k``s``s`ks``s`kk``s`ksk`k``
s``s`ks``s`kk``s`ks``s`k`sik`kk`k``s`kk``s``s`k``s``s`kski``s``s`ks``s`kk``s`k
s``s`k`sik`kk``s`k`s``si`k``si`k``si`k``s``s`ksk`k``s``s`ks``s`k`si``s`kk``s`k
`si``s`kk``s`k`s`kk``s`k`sikk``s`kk``s`k`s``si`k``si`k``si`k``s`k`si``s`kk``s`
k`s``s`ksk``s`kk``s``s`ks``s`kk``s`ksk`k``s`k`s``s`ks``s`k`si``s`kk``s`k`sik``
s`kkk``s`kk``s`k`s``si`k``si`k``si`k``s`kk``si`k`k`k`k```sii```sii``s``s`kski`
`s`kk``s``s`k``s``s`ksk``s``s`kski``s``s`ks``s`kk``s`ks``s`k`sik`kk``s`k`s``si
`k``si`k``si`ki``s`kk``s``s`ks``s`k`sik``s`kk``s`k`s``si`k``si`k``si`k``s``s`k
sk`k``s``s`ksk`k``s`k`s``s`ksk``s`kk``s`k`s`kk``s`k`sik``s`kk``s``s`k``s``s`ks
ki``s`k``s``s`ksk``s``s`kski``s``s`ks``s`kk``s`ks``s`k`sik`kk``s`k`s``si`k``si
`k``si`k``s``s`ksk`k`s`k`s`k``s`k`s``si`k``s`k``s``s`kski``s``s`ksk```sii``s``
s`kskik``s`kk``s`k`s``si`k``si`k``si`k``s``s`ksk`k``s``s`ksk`k``s`k`s``s`ksk``
s`kk``s`k`s``s`ksk``s`kk``s`k`s`k`s``s`ksk``s`k`s`kk``s``s`ks``s`kk``s`ks``s`k
k``s`ks``s``s`ksk`k``s`k`sik`k``s``s`ks``s`kk``s`ks``s`k`s`ks``s`k`s`k`si``s`k
`s`kk``s``s`ksk`k``s`k`sik`k``s`kkk``s`kk``s``s`k``s``s`kski``s``s`ks``s`kk``s
`ks``s`k`sik`kk``s`k`s``si`k``si`k``si`k```sii``s`k`s``s`ksk``s`kk``s`k`s`kk``
s`k`si``s`kk``sii``s`kk``s``s`k``s``s`ksk```sii``s``s`kski``s``s`ks``s`kk``s`k
s``s`k`sik`kk``s`k`s``si`k``si`k``si`k``s``s`ksk`k``s``s`ks``s`k`s`ks``s`k`s``
s`ks``s``s`ksk`k``s`k`si``s`kk``s``s``s`k``si`kk``s``s``si`kk`k``si`k`ki`k````
`sii```sii``s``s`kski``s`k`s``si`kkk`k`ki``s`k`s``s`ksk``s`kk``s`ks``s`kk``s`k
s```ss`s``s`ks``s`kk``s`ks``s`k`si```ss`si`kk`kk`k```sii``s`k`s``s`ksk``s`kk``
s`k`s`kk``s`k`si``s`kk``sii``s`kkk`k`ki``s`kk```ss`s``s`ks```ss`s``s`ks``s`kk`
`s`ks``s`k`sik`kk`k``sii``sii`k`k``s`k`s``si`k``s``s`ksk``s`k``s``s`kski`````s
ii``s``s`kski`s``s`ksk```sii``s``s`ksk``s``s`kskik`kk`k`k``si`k`ki``s``s`ks``s
`kk``si`k`k`k`k```sii```sii``s``s`kski`k``s`k`s``si`k```sii```sii``s``s`kskik
    |]
main = output . eval =<< (program :$) . encode <$> getContents

Unlambda インタプリタなので、コンパイルして、実行して、標準入力に Unlambda プログラム *4 を流し込むと、実行できます。当たり前ですが。

$ ghc --make unlambda.hs 
[2 of 2] Compiling Main             ( unlambda.hs, unlambda.o )
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package pretty-1.1.1.0 ... linking ... done.
Loading package array-0.4.0.0 ... linking ... done.
Loading package deepseq-1.3.0.0 ... linking ... done.
Loading package containers-0.4.2.1 ... linking ... done.
Loading package template-haskell ... linking ... done.
Linking unlambda ...

$ ./unlambda < fibonacci.unlambda | head

*
*
**
***
*****
********
*************
*********************
**********************************

github リポジトリはこちら → https://github.com/h-hirai/LazyKQQ

Unlambda でなく Lazy K セルフインタプリタとかでも面白いと思います。今回、Lazy K 処理系自体は Lazy K セルフインタプリタのお守り *5で有名 (?) な @fumieval さんのインタプリタ *6 をほぼそのまま使わせていただいています。

書き換えた部分は、parse 関数くらいで、こんな感じになってます。もともとは Expr を返すようになっていたのを ExpQ を返すように書き換えたわけですね。

parse :: String -> (ExpQ, String)
parse ('`':xs) = let (a0, xs') = parse xs
                     (a1, xs'') = parse xs' in
                 (infixE (Just a0) (conE '(:$)) (Just a1), xs'')
parse ('s':xs) = ([|S|], xs)
parse ('k':xs) = ([|K|], xs)
parse ('i':xs) = ([|I|], xs)
parse (_:xs) = parse xs
parse "" = ([|I|], "")

で、QuasiQuoter として使えるようにするためには、この parse を QuasiQuoter 値コンストラクタでラップして lazyK 変数に束縛します。

lazyK = QuasiQuoter { quoteExp = fst . parse
                    , quotePat = undefined
                    , quoteType = undefined
                    , quoteDec = undefined
                    }

あと、準クォートなしの Template Haskell と同様に、利用側より先にコンパイルされるように、別モジュールにする必要があります。

余談

もともと main はこのように書いてました。

main = do
  input <- getContents
  output $ eval $ program :$ (encode input)

これを、もともとの @fumieval さんのコードを参考に、このように書き換えてみたりしたわけなんですが、

main = output . eval =<< (program :$) . encode <$> getContents

……書き換える前の方が読みやすい気がする。

Template Haskell のお勉強ちう、そのに &dash; runIO

Template Haskell のお勉強ちう - 日曜プログラマがダラダラ書く のつづきです。

githubリポジトリはこちら → https://github.com/h-hirai/SimpleRayTracer

結果的にすごい簡単になったというおはなし。

前回、あまり大きなリストリテラルを作ると、ghc が落ちるので、あまり大きな画像は (というか、かなり小さな画像しか) レンダリングできないというところで終わりました。

さて、前回もリンクしました @mr_konn さんによるチュートリアルによりますと、Q モナドの中では任意の IO 処理が実行できます。じゃぁ、もういっそファイル書き出しまでコンパイル中に実行しちゃえばいいような気がする……、と思って書いたコードが以下になります。

{-# LANGUAGE TemplateHaskell #-}

module RayTracerTH where

import Language.Haskell.TH

import RayTracer
import Vector3D

import Codec.BMP

runTrace :: World -> Vector3D ->
            Float -> Float -> Float -> Float -> Float ->
            ExpQ
runTrace w eyePos startx endx starty endy step = do
  runIO $ writeBMP "result.bmp" $ trace w eyePos startx endx starty endy step
  tupE []

前回の RayTracerTH と違い、RayTracer.trace をそのまま使用する形になっています*1。というか、ほとんど通常版レイトレーサの main の内容が runIO の中に引っ越してきただけです。

呼び出し側になる main はこんなかんじ

{-# LANGUAGE TemplateHaskell #-}

module Main where

import RayTracerTH
import RayTracer (world_b, world_c, eyePos)

main :: IO ()
main = return $(runTrace (world_b ++ world_c) eyePos (-96) 96 (-54) 54 1.0)

これで、

$ ghc --make ray_tracer_th.hs

のようにビルドすると、実行ファイル ray_tracer_th と一緒に result.bmp ができます。通常板レイトレーサと同じ程度の出力サイズでも問題なくレンダリングでき、レンダリング (コンパイル) 時間も同程度になりました。*2

一方、ray_tracer_th を実行しても何も起こりません。上記の main は、接合後には

main :: IO ()
main = return ()

のようになっているはずです。

……というか、こんな main や実行ファイルは不要ですね。消してしまいましょう。runTrace もなくなって、RayTracerTH はこんなかんじになります*3

{-# LANGUAGE TemplateHaskell #-}

module RayTracerTH where

import Language.Haskell.TH
import Codec.BMP
import RayTracer

do
  runIO $ writeBMP "result.bmp" $
        trace (world_b ++ world_c) eyePos (-96) 96 (-54) 54 1.0
  return []

実行ファイルも作りませんので、このモジュールだけをただコンパイルして、result.bmp を作ります。*4

$ ghc --make RayTracerTH.hs

えー……、もはや runghc となにが違うのか。ここまでくると、処理が実行時に行われようが、コンパイル時に行われようが同じじゃん、という感じになってきます。ほんとにスクリプト言語のプログラムを実行してる気分。

と、このように、Template Hasekell によるコンパイルレイトレーシングは、通常のレイトレーサに、ごく薄いラッパをかぶせるだけで実現できることが分かりました。

……ぶっちゃけ、これではネタ的にぜんぜん面白くありません。とりあえず、今後はコンパイル時とか言わずに、普通のレイトレーサとして気が済むまで改良してみようかな、とか思ってます。これといって特殊なお話にはならないと思うので、ここではこれのお話はここまで*5

これとは別に、Quasi Quote を使ったしょーもないネタがあるので、うまくいったら、そのさん、はそれで。

*1:trace もちょっとだけ整理しましたが本題と無関係なので省略

*2:2012-06-08 追記 : 最適化も、当たり前ですが、効きます

*3:なにこの do ? って思った方は、こんさんのチュートリアルをよく読みましょう

*4:2012-06-05 修正: -c オプションではなく --make オプションでコンパイルします

*5:すごいくだらない番外編が一回あるかも

Template Haskell のお勉強ちう

ご注意

この記事で Template Haskell の解説はいたしません。それについては、@mr_konn さんによるチュートリアルが大変分かりやすいので、そちらをご参照ください。

私はまだ前半分しか読んでませんけどね!

前置き

Yesod なりなんなり、他人様のコードを読ませてもらって Haskell のお勉強をしようにも、Template Haskell が分からないとどれも読めない、という感じになってきましたので、ちょっくら自分で Template Haskell を使ったコードを何か書いてみようと思いました。

で、コンパイル時プログラミングと言えばレイトレーシングだよね!*1 ということで、まず、普通にレイトレーサを書いてみました (初手から脱線*2 )。書いたコードはこちら→ https://github.com/h-hirai/SimpleRayTracer

Paul Graham 著「ANSI Common Lisp (スタンダードテキスト)」にある例をベタに移植したもので、反射、透過、屈折などなどなにもなし、多分レイトレーサとしては一番簡単なやつです。そのままだと出来上がる画像があんまりさみしいので色を付けたのと、BMP を出力するようにしたくらいが変更点。*3

こんな画像を生成できます。オブジェクトの数にすごい依存しますが、2010年モデルの MacBook Air で1分くらい? *4


で、これをコンパイル時に計算させる

コンパイル時プログラミングの用途ってそうじゃないだろう、というツッコミが己のうちから聞こえてきます。無視しますが。

まず、ふつうのレイトレーサを書いた時、最終段階の trace 関数がこんなかんじでした。*5

trace :: World -> Vector3D -> Float -> Float -> Float -> Float -> Float -> BMP
trace w eyePos startx endx starty endy step =
  packRGBA32ToBMP width height $
  B.concat [packCol $ colorAt w eyePos col row |
          row <- [starty, starty + step .. endy],
          col <- [startx, startx + step .. endx]]
  where
    width = 1 + floor ((endx - startx) / step)
    height = 1 + floor ((endy - starty) / step)

これを、main では以下のように呼びます。もともとは RayTracer.hs のなかで main まで定義していたのですが、Template Haskell 版を作る際に、main は ray_tracer.hs に分けました。

main :: IO ()
main = writeBMP "result.bmp" $
       trace (world_b ++ world_c) eyePos (-96) 96 (-54) 54 0.2

んで、

コンパイル時に計算させるにあたって、RayTracer モジュールを wrap するかたちで RayTracerTH を定義しました。これで定義しなおされている trace を、main で以下のように呼びます。(ray_tracer_th.hs)

main :: IO ()
main =
  let startx = -96
      endx = 96
      starty = -54
      endy = 54
      step = 0.2
      width = 1 + floor ((endx - startx) / step)
      height = 1 + floor ((endy - starty) / step) in
  writeBMP "result.bmp" $
  packRGBA32ToBMP width height $
  pack $ $(trace (world_b ++ world_c) eyePos (-96) 96 (-54) 54 0.2)

RayTracerTH.trace は ExpQ を返して、それを main で接合します。もとの RayTracer.trace では BMP を返していましたが、こちらでは接合結果 (って言い方であってます?) がリストリテラルになるイメージ。なので、trace でやっていた pack, packRGBA32ToBMP が TH 版では main に来ています。BMP 型や ByteString 型の値の ExpQ が作れるのかどうかは分かりません。

あと、let で束縛されている変数は $() の中では参照できません。ので、trace には即値を渡したりしています。このへんあとで要整理。

さて、その RayTracerTH.trace は以下のように書き換えました。

trace :: World -> Vector3D ->
         Float -> Float -> Float -> Float -> Float ->
         ExpQ
trace w eyePos startx endx starty endy step = do
  let ws = concat [packCol $ colorAt w eyePos col row |
                   row <- [starty, starty + step .. endy],
                   col <- [startx, startx + step .. endx]]
  listE $ map (litE . integerL . fromIntegral) ws

出力画像の一画素ごとに colorAt を呼ぶところまでは、もとと同じです。packCol は、もとは Color -> ByteString 型の関数でしたが、RayTracerTH で Color -> [Word8] に書き直されています。最後の行で、計算されたリストを ExpQ に変換します。

たったこれだけの変更で、レイトレーシングコンパイル時にできるようになります、すごい!

と、思いきや

ghc: sorry! (unimplemented feature or known bug)
  (GHC version 7.0.4 for i386-apple-darwin):
	Trying to allocate more than 1040384 bytes.

See: http://hackage.haskell.org/trac/ghc/ticket/4505
Suggestion: read data from a file instead of having large static data
structures in the code.

orz

しかたないので、小さい画像サイズでとにかく動かしてみます。trace の引数 step が小さいほど画像解像度が高くなりますので、これを逆に大きくします。2.0 まで大きくしてやっとコンパイルが通るようになりました。

実行して出力される画像がこちら。

このちっさい画像を生成 (というかコンパイル) するのにかかる時間が、大体 50 秒くらいで、上の画像を実行時に生成するのとほとんど変わりない時間かかってます。

時間のことはしかたないとして、もとと同程度のサイズで出力できるようにする回避策を考え中。

*1: constexpr - Google 検索

*2:そもそも何のコードを読みたくて Template Haskell の勉強をしようと思ったのか忘れた。

*3:Codec.BMP を使用していて、これは cabal でインストールできます。

*4:2012-06-08 追記 : -O オプションを付けて最適化コンパイルすると10秒程度で終わります

*5:width と height の計算がたぶん間違っています。

深く考えずに Mighttpd をさわってみた (2)

そもそもの大間違いとして、インストールするべきパッケージは mighttpd ではなく mighttpd2だということに気づいてしまったので、最初からやりなおしです。

$ cabal install mighttpd2

ドライランとかしません、依存パッケージとかは HackageDB を参照してください。

……さて、mighttpd2 というコマンドがインストールされるのかと思いきや、意表をついて mighty らしいです。とりあえず実行してみます。

$ mighty 
Usage: mighty config_file routing_file

$

mighttpd とほんとんど変わらないみたいですね。map_file は routing_file という名前になったらしいです。

昨日と同じように、~/Library/Haskell/ghc-7.0.3/lib/mighttpd2-2.3.0/share/ にあるサンプルファイルを trial.conf、trial.route としてコピーし、trial.route のほうは以下のように編集します。

# Sample routing for Mighttpd 2

# Domain lists
[localhost]

# Entries are looked up in the specified order
# All paths must end with "/"

# A path to static files should be specified with "->"
/                -> /Users/hirai/MighttpdTrial/

あと、sample.conf のDebug_Mode は最初から Yes でした。

どりゃ。

$ mighty trial.conf trial.route
bind: permission denied (Permission denied)

$

……昨日といっしょ。

では、sudo つけて実行してみましょうかー。

$ sudo mighty trial.conf trial.route
Password:

……お? プロンプトが返って来ないですね。なんか動いてるっぽい? ので、ブラウザで http://localhost/ にアクセスしてみると、

Not Found

とだけのそっけない表示。おぉ、動いてるっぽい。ターミナルのほうは、

127.0.0.1 - - [11/Aug/2011:23:47:03 +0900] "GET / HTTP/1.1" 404 11 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.107 Safari/535.1"
127.0.0.1 - - [11/Aug/2011:23:47:03 +0900] "GET /favicon.ico HTTP/1.1" 404 11 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.107 Safari/535.1"

こんなかんじ。動いたようですねー。

じゃ、こんなファイルを置いてみましょうか。

<html>
<body>
<h1>Hello, Mighttpd!</h1>
</body>
</html>

おけおけ。今日はここまでにしましょう。

次は CGI、……かなぁ? あー、そのまえに root 権限なしで動かしたいかなぁ。

深く考えずに Mighttpd をさわってみた (1)

(2011-08-12 追記)

そもそも mighttpd は今じゃ古いパッケージで、インストールするべきなのは mighttpd2 だったということを翌日思い出しました。そのようなわけで、以下の記事は、まったく無意味です。

id:h-hirai:20110812:1313075661 をご参照ください。

(追記、ここまで)

Haskell をチェックしている人ならご存知でしょうが、Mighttpd ("まいてぃ"と読むそうです) は Mew や Firemacs の山本和彦さん (ご本人は Haskell の山本さんと呼ばれたいらしい) が作っていらっしゃる、Haskell で書かれた高速な Web サーバみたいです。

インストール

Haskell Platform をインストールしていれば、パッケージ管理システムコマンド cabal もインストールされています。これで Mighttpd もインストールできます。

とりあえず、ドライランしてみる。

$ cabal install --dry-run -v mighttpd
Reading available packages...
Resolving dependencies...
In order, the following would be installed:
c10k-0.4.1 (new package)
hslogger-1.1.4 (new package)
hsyslog-1.4 (new package)
hdaemonize-0.4.4 (new package)
webserver-0.4.4 (new package)
mighttpd-0.4.3 (new package)

なんか、依存パッケージが少しありますが、まぁ、気にせずいきましょう。

$ cabal install mighttpd
(標準出力略)

なお、cabal コマンド実行時に sudo は必要ありません。ホームディレクトリ以下にインストールされます。スタート Haskell でトラヴィスさんがおっしゃっていましたね*1

……で?

すこし Warning は出ているものの、cabal install は特に問題なく終了した模様。

それで、……どうしよう?

とりあえず、~/Library/Haskell/bin/ に mighttpd がインストールされたので、ただ実行してみましょうか?

上記ディレクトリにパスはとおしてあるので、

$ mighttpd 
Usage: mighttpd config_file uri_map

……ふむ。

~/Library/Haskell/ghc-7.0.3/lib/mighttpd-0.4.3/share/ に sample.conf と sample.map があるので、多分、これらが Usage にある config_file と uri_map に対応しますな? とりあえず、これらを trial.conf、trial.map としてコピーしてみましょう。

trial.conf はそのまま、trial.map は以下のように編集してみました。

# Directory mapping
http://localhost/ -> /Users/hirai/MighttpdTrial

で、ファイルを指定して、実行……。

$ mighttpd trial.conf trial.map 

$

さて、エラーとかは出ず、プロンプトが返ってきましたが。

……ダメですね。ブラウザで http://localhost/ にアクセスしてみても、エラー画面しか見えません。ps でもそれらしいプロセスは見当たらないです。

trial.conf を一部、編集して実行してみましょうか?

Debug_Mode: Yes

で、

$ mighttpd trial.conf trial.map 
bind: permission denied (Permission denied)

ふむ。

sudo で実行すれば動きそうだけど、んー、……今日はここまで。

*1:参加してない。Ust で聞いた

MacPorts で Scala 2.9 と Emacs の scala-mode を使えるようになるまで

$ sudo port install scala29

すると、"-2.9" という postfix がついた処理系一式の他に、依存性解決で scala_select という port もインストールされるので、

$ sudo scala_select scala29

で、処理系のそれぞれのコマンドがシンボリックリンクされて、scala, scalac などが使えるようになる。

(2012-11-17: 追記)

scala_select は port コマンド内に取り込まれて (?)、上記コマンドは以下のように変わっている。(ついでにバージョンも上がっている。)

$ sudo port select scala scala2.10

(追記ここまで)

scala-mode は scala29 のインストールの中に含まれるので、~/.emacs.d/init.el などに以下の行を追加する。

(add-to-list
 'load-path
 "/opt/local/share/scala-2.9/misc/scala-tool-support/emacs")
(require 'scala-mode-auto)

C++ のキャストと void ポインタ

unsigned int uia[8];
unsigned char uca[8];

void test() {
  void* vp;
  unsigned int* uip;
  unsigned char* ucp;

  uip = uia;
  ucp = uca;

  vp = uia;
  // uip = vp; // Error!
  uip = static_cast<unsigned int*>(vp);

  vp = uca;
  // ucp = vp; // Error!
  ucp = static_cast<unsigned char*>(vp);

  // ucp = uia; // Error!
  // ucp = static_cast<unsigned char*>(uia); // Error!
  ucp = reinterpret_cast<unsigned char*>(uia);

  // uip = uca; // Error!
  // uip = static_cast<unsigned int*>(uca); // Error!
  uip = reinterpret_cast<unsigned int*>(uca);

  vp = uia;
  ucp = static_cast<unsigned char*>(vp);

  vp = uca;
  uip = static_cast<unsigned int*>(vp);

  ucp = static_cast<unsigned char*>(static_cast<void*>(uia));
  uip = static_cast<unsigned int*>(static_cast<void*>(uca));
}