Template Haskell のお勉強ちう、そのに ‐ 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:すごいくだらない番外編が一回あるかも