Reputation: 1507
I thought about making a Direction data type and I'd like to have each element associated with a 3d Vector indicating the x, y and z value of the direction. Up, for instance, would have the value 0 1 0. What is a good way to do this?
data Direction = None | Up | Right | Down | Left | Above | Below deriving (Enum)
Is doing as below really the best way?:
direction :: Direction -> Point3
direction Up = Point3 0 1 0
direction GameEngine.Right = Point3 1 0 0
direction Down = Point3 0 (-1) 0
direction GameEngine.Left = Point3 (-1) 0 0
direction Above = Point3 0 0 1
direction Below = Point3 0 0 (-1)
direction None = Point3 0 0 0
Upvotes: 1
Views: 200
Reputation: 11888
As suggested by n.m., you can use an Array.
{-# LANGUAGE NoImplicitPrelude #-}
import Data.Array
import Prelude hiding (Left, Right, abs)
data Direction = None | Above | Below | Up | Down | Right | Left deriving (Enum, Ord, Eq, Ix)
-- helper function for finding absolute value of Point3
abs (Point3 x y z) = sqrt $ fromIntegral $ x^2 + y^2 + z^2
-- written long way using do-notation
dir :: Array Direction Point3
dir = listArray (None, Left) states
where
moves = [0, 1, -1]
states :: [Point3]
states = do
x <- moves
y <- moves
z <- moves
let point = Point3 x y z
guard $ abs point <= 1
return point
-- written short way using list-comprehension
dir :: Array Direction Point3
dir = listArray (None,Left) [p |
x <- m, y <- m, z <- m,
let p = Point3 x y z,
abs p <= 1
] where m = [0, 1, -1]
Indexing into the array by Direction
will give you a Point3
.
>>> dir ! Above
Point3 0 0 1
This will give you a slight performance advantage over a function because you will have permanent cache of pre-constructed Point3
s and hence, will not cause any allocation.
The other bonus is that the code is pretty neat!
The disadvantage is that it requires Direction to be Ord, Eq and Ix.
Upvotes: 1