Haskellでレンダラーを書いてみるテスト #01: ベクトル型定義

いきなりここで詰まる。

追記:ここのHaskellレイトレ比較記事によるとtuple使うのはよくないらしい。後で参考にして書き直す。(ソースレポジトリが落ちてるぽい)

最初の案

-- Vector3.hs
-- 3D Vector type definitions
module Vector3 where

type REAL = Double

data Vector3 = Vector3 (REAL, REAL, REAL) deriving (Eq, Show, Read)
	
instance Num Vector3 where
	Vector3 (xa, ya, za) + Vector3 (xb, yb, zb) = Vector3(xa + xb, ya + yb, za + zb)

ここで問題になるのは、+演算子。これを定義するためにNumクラスのインスタンスとしてしまうと、他に*演算子、abs, sigNum, fromInteger等の関数定義が必須になってしまう。

2番目の案

-- Vector3.hs
-- 3D Vector type definitions
module Vector3 (
	REAL,
	Vector3,

	vadd, vsub, vdotp, vcrossp
	) where

type REAL = Double

type Vector3 = (Double, Double, Double)

vadd :: Vector3 -> Vector3 -> Vector3
(xa, ya, za) `vadd` (xb, yb, zb) = (xa + xb, ya + yb, za + zb)

vsub :: Vector3 -> Vector3 -> Vector3
(xa, ya, za) `vsub` (xb, yb, zb) = (xa - xb, ya - yb, za - zb)

vdotp :: Vector3 -> Vector3 -> REAL
(xa, ya, za) `vdotp` (xb, yb, zb) = xa*xb + ya*yb + za*zb

vcrossp :: Vector3 -> Vector3 -> Vector3
(xa, ya, za) `vcrossp` (xb, yb, zb) = (ya*zb - za*yb, za*xb - xa*zb, xa*yb - ya*xb)

こんなかんじ。

ユニットテスト

ユニットテストを書くのにはまっているのでHaskellでもそんな感じでいくことにする。

軽くググって、HUnitをつかってみることに。ghcに標準添付されている?のかghc-pkgによると既にインストール済みのようだ。

-- Vector3Test.hs : Vector3 module test

import Vector3
import Test.HUnit

testvadd = TestCase $ assertEqual "testing (1, 2, 3) + (3, 2, 1)"
	(4, 4, 4) ((1, 2, 3) `vadd` (3, 2, 1))

testvsub = TestCase $ assertEqual "testing (1, 2, 3) - (3, 2, 1)"
	(-2, 0, 2) ((1, 2, 3) `vsub` (3, 2, 1))

testvdotp = TestCase $ assertEqual "testing (1, 2, 3) dotp (3, 2, 1)"
	10 ((1, 2, 3) `vdotp` (3, 2, 1))

testvcrossp = TestCase $ assertEqual "testing (1, 2, 3) crossp (4, 5, 6)"
	(-3, 6, -3) ((1, 2, 3) `vcrossp` (4, 5, 6))

main = runTestTT $ TestList [testvadd, testvsub, testvdotp, testvcrossp]

実行結果:

kouhei@snowshoe:~/svnwork/nyatr/trunk$ ghci Vector3Test.hs 
GHCi, version 6.8.2: http://www.haskell.org/ghc/  :? for help
Loading package base ... linking ... done.
[1 of 2] Compiling Vector3          ( Vector3.hs, interpreted )
[2 of 2] Compiling Main             ( Vector3Test.hs, interpreted )
Ok, modules loaded: Main, Vector3.
*Main> main
Loading package HUnit-1.2.0.0 ... linking ... done.
Cases: 4  Tried: 4  Errors: 0  Failures: 0
Counts {cases = 4, tried = 4, errors = 0, failures = 0

とりあえず今日はこんなところで。

ここまでのソースコードhttp://websvn.nyaxtstep.com/viewvc.cgi/nyatr/trunk/?pathrev=622