IsVec2 and vector class
shoooe opened this issue · 2 comments
The following is definitely low priority and possibly away from the author's intent for this library, especially considering that it doesn't mimic Elm. But I also think that this is an opportunity to make helm interface more "open world friendly", given that Haskell has a much wider public than Elm which is specific to its own web-restricted world.
Haskell's support for math with pairs is basic to say the least. This often leads the user of this library, to have to define a vector class of its own, with its own definition of Applicative
, Functor
and Num
to make things a little better. An example is this:
data Vec2 a = Vec2 a a deriving (Eq, Show)
instance Functor Vec2 where
fmap fn (Vec2 a b) = Vec2 (fn a) (fn b)
instance Applicative Vec2 where
pure a = Vec2 a a
(Vec2 fa fb) <*> (Vec2 a b) = Vec2 (fa a) (fb b)
instance (Num a) => Num (Vec2 a) where
(+) = liftA2 (+)
(*) = liftA2 (*)
abs = fmap abs
signum = fmap signum
fromInteger = pure . fromInteger
negate = fmap negate
magnitude :: Floating a => Vec2 a -> a
magnitude (Vec2 ax ay) = sqrt $ (ax ^^ (2 :: Int)) + (ay ^^ (2 :: Int))
normalize :: Floating a => Vec2 a -> Vec2 a
normalize v = liftA2 (/) v (pure . magnitude $ v)
The user will then need to define its own version of fromPair
and toPair
to later interact with helm.
One way to solve this would be to provide a Vec2
class for the library itself, but the user might need to use other vector data structures of their own (due to compatibility with other libraries; for example a physic library).
What if we define a simple class:
class IsVec2 vec where
toPair :: vec a -> (a, a)
fromPair :: (a, a) -> vec a
-- utility functions
getX :: IsVec2 => vec a -> a
getX = fst . toPair
getY :: vec a -> a
getY = snd . toPair
and then modify the interface so that it accepts and return any IsVec2
structure polymorphically? An example would be:
arrows' :: IsVec2 vec => Bool -> Bool -> Bool -> Bool -> vec Int
arrows' u l d r = fromPair $ (-1 * fromEnum l + 1 * fromEnum r, -1 * fromEnum u + 1 * fromEnum d)
or:
move :: IsVec2 vec => vec Double -> Form -> Form
move v f = f { formX = (getX v) + formX f, formY = (getY v) + formY f }
so the user could use move
, and all the functions that currently accept or return pairs, directly with their own data structures:
move (Vec2 1 1) $ ...
In addition to this, we could provide a Math
/Vector
module that could contain a Vec2
data like above for the user to use directly if they have no other preferences.
There's two sides to what people would like Helm to continue on, some want it to copy Helm strictly and others want it only to mimic it slightly. I'm on both sides at the moment, leaning mainly towards the strict copy side.. so I'm going to say no to this sort of thing being part of the main library. But we could certainly make this sort of thing part of the extras library.
But we could certainly make this sort of thing part of the extras library.
Nah, no need to duplicate a library for this. Thanks for the attention though. :)