2009年8月16日日曜日

Haskellでレイトレーシング(第5回)〜タプルを返せる

Haskellでは、関数の戻り値としてタプルを返すことができます。

今回は、タプルを返す場合についてCommon LispとHaskellでの書き方の違いを書きます。

Common Lispでタプルを返す場合は、以下のようにvalues関数で値を返して、multiple-value-bindでその値を受け取ります。
(defun sendray (pt xr yr zr)
(multiple-value-bind (s int) (first-hit pt xr yr zr)
(if s
(* (lambert s int xr yr zr) (surface-color s))
0)))

(defun first-hit (pt xr yr zr)
(let ...略...
(values surface hit)))
first-hitがレイと交差した面とその交点の組を返す関数です。それをsendrayから呼び出して、multiple-value-bindで受け取っています。

一方、Haskellではこのように書きます。
sendray :: [Surface] -> Light -> Point ->
Double -> Double -> Double -> Color
sendray world light pt xr yr zr =
case first_hit world pt xr yr zr of
Just (s@(Sphere (Color col) _ _ _), int)
-> Color ((lambert s int light) * col)
Nothing
-> Color 0.0

first_hit :: [Surface] -> Point ->
Double -> Double -> Double ->
Maybe (Surface, Point)
first_hit world pt xr yr zr = nearest (map hit world)
where nearest :: [Maybe (Double, Surface, Point)]
-> Maybe (Surface, Point)
nearest hits = case foldr cmp Nothing hits of
Just (d, s, h) -> Just (s, h)
otherwise -> Nothing

...略...
first_hitでMaybe (Surface, Point)型を返し、それをsendrayでパターンマッチで受け取っています。Haskellでは、タプルを返すのに関数をはさむ必要はなく、そのまま書くことができます。

次回は、「5.衝突点の計算」について書きます。


■他の記事
Haskellでレイトレーシング(第1回)〜導入
Haskellでレイトレーシング(第2回)〜ループは使わない
Haskellでレイトレーシング(第3回)〜型による分岐にはパターンマッチを用いる
Haskellでレイトレーシング(第4回)〜NilはMaybeモナドで表現する
Haskellでレイトレーシング(第5回)〜タプルを返せる

0 件のコメント: