Mind the following code:
-- A n-dimensional axis aligned bounding box.
data AABB v a = AABB {
aabbMin :: !(v a),
aabbMax :: !(v a)
} deriving (Show)
-- `v` is a container, representing the number of dimensions. Ex:
-- type Box2DFloat = AABB V2 Float
-- type Box4DFloat = AABB V4 Float
-- A n-dimensional ray.
data Ray v a = Ray {
rayPos :: !(v a),
rayDir :: !(v a)
} deriving (Show)
-- Traces a n-d ray through a n-d box, returns
-- the intersection indexes (tmin, tmax).
intersectAABB
:: (Foldable f,
Metric f,
Ord a,
Num (f a),
Fractional (f a),
Floating a)
=> Ray f a
-> AABB f a
-> [a]
intersectAABB (Ray rayPos rayDir) (AABB aabbMin aabbMax)
= [tmin, tmax] where
t1 = (aabbMin - rayPos) / rayDir
t2 = (aabbMax - rayPos) / rayDir
tmin = foldr1 max $ liftI2 min t1 t2
tmax = foldr1 min $ liftI2 max t1 t2
That is an usual Ray→AABB intersection function, and it is pretty simple and clean, except for the type signature, which is almost bigger than the function itself! Someone suggested I could use kind constraints that "encapsule my needs" to make it less verbose, but I can't find a kind constraint that "encapsules my needs" properly. "My needs", on this case, are basically "the type acts like a number should". So, on my mind, the following would make sense:
class Real a where
... anything I want a real number to do ...
instance Real Float where
...
instance (Real a) => Real (V2 a) where
...
instance (Real a) => Real (V3 a) where
...
type AABB a = V2 a
type Ray a = V2 a
type Box2DFloat = AABB (V2 Float)
type Box4DFloat = AABB (V4 Float)
type Ray2D a = Ray (V2 a)
type Ray3DRatio = Ray (V3 Ratio)
... etc ...
That way, my signatures would become, simply:
intersectAABB :: (Real r, Real s) => Ray r -> AABB r -> [s]
Which looks much better. But, if nobody using Haskell has bothered to define such class, there should be a reason. What is the reason there is no "Real" class, and, if defining such a class would be a bad idea, what is the proper solution to my issue?
Use constraint synonyms:
{-# LANGUAGE ConstraintKinds #-}
type ConstraintSynonym f a = (
Foldable f,
Metric f,
Ord a,
Num (f a),
Fractional (f a),
Floating a)
With ConstraintKinds
, lifted tuples can be used to express conjunction of constraints (and ()
can refer to the trivially satisfied constraint). You can now use ConstraintSynonym
instead of the big tuple of constraints in annotations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With