My thoughts so far were:
Types
a hypercube is a (discrete) function from one or more Dimensions to some value. I wanted to use Enumeration types for the Dimensions and ended up with this typeclass:
class (Eq a, Ord a, Show a, Enum a, Bounded a) => Dimension a
which allowed me to use this
data Age = Young | Adult | Old deriving (Eq, Ord, Show, Enum, Bounded)
instance Dimension Age
and similar types as Dimensions.
A 2dimensional cube where the values have the type Double then has the type
cube2D :: (Dimension a, Dimension b) => a -> b -> Double
Operations
I can rotate the cube easily:
cube2D' p a = cube2D a p
I can get all possible values ("arguments") of a Dimension and for a 1D cube I can also get the possible results
arguments :: Dimension a => [a]
arguments = enumFrom minBound
results :: (Dimension a) => (a -> r) -> [r]
results cube = fmap cube arguments
This allows me to collapse a cube by one dimension, e.g. by replacing it by the sum of all results:
sum2D :: (Dimension a, Dimension b, Num r) => (a->b->r) -> a -> r
sum2D = fmap (sum . results)
So far so good
but sum2D only works for a cube with two Dimensions. I can write a similar function for a 3D cube and another one for a 4D cube. I suspect that most yet-to-be implemented operations will face the same problem. That means, my abstraction of Hypercube isn't really worth its salt.
I am not sure if I started on the wrong foot, or if my attempt to have an arbitrary number of Dimensions just doesn't go well with type-safety.
Any suggestions will be much appreciated.