{-# OPTIONS -Wall -O2 #-}

module Graphics.UI.HaskGame.Vector2
    (Vector2(Vector2)
    ,vector2
    ,first,second,(***),both
    ,fst,snd)
where

import Prelude hiding (fst, snd)
import Control.Applicative(Applicative(..), liftA2)
import Control.Monad(join)

data Vector2 a = Vector2 !a !a
  -- Note the Ord instance is obviously not a mathematical one
  -- (Vectors aren't ordinals!). Useful to have in a binary search
  -- tree though.
  deriving (Eq, Ord, Show, Read)

type Endo a = a -> a

fst :: Vector2 a -> a
fst (Vector2 x _) = x

snd :: Vector2 a -> a
snd (Vector2 _ y) = y

first :: Endo a -> Endo (Vector2 a)
first f (Vector2 x y) = Vector2 (f x) y

second :: Endo a -> Endo (Vector2 a)
second f (Vector2 x y) = Vector2 x (f y)

(***) :: Endo a -> Endo a -> Endo (Vector2 a)
(f *** g) (Vector2 x y) = Vector2 (f x) (g y)

vector2 :: (a -> a -> b) -> Vector2 a -> b
vector2 f (Vector2 x y) = f x y

both :: Endo a -> Endo (Vector2 a)
both = join (***)

instance Functor Vector2 where
  fmap f (Vector2 x y) = Vector2 (f x) (f y)
instance Applicative Vector2 where
  pure x = Vector2 x x
  Vector2 f g <*> Vector2 x y = Vector2 (f x) (g y)

-- An improper Num instance, for convenience
instance (Eq a, Show a, Num a) => Num (Vector2 a) where
  (+) = liftA2 (+)
  (-) = liftA2 (-)
  (*) = liftA2 (*)
  abs = fmap abs
  negate = fmap negate
  signum = fmap signum
  fromInteger = pure . fromInteger