module RIVSDef where

-- A “real inner-product vector space” is a vector space that has an inner
-- product (e.g., dot product for ℝ²), using real numbers (let's say Double) for
-- scalars.  It supports the following operations:

class RIVS a where
    -- zero vector
    zero :: a
    -- adding two vectors
    plus :: a -> a -> a
    -- additive inverse, plus v (neg v) = zero
    neg :: a -> a
    -- subtracting two vectors
    minus :: a -> a -> a
    -- multiplying by scalar
    scale :: Double -> a -> a
    -- inner product
    dot :: a -> a -> Double

    -- Default implementations so you just override one of {minus, neg}
    minus u v = plus u (neg v)
    neg v = minus zero v


-- The benefit of having RIVS is that algorithms for inner-product spaces can be
-- coded up polymorphically, e.g.,

-- Split a vector into two parts: projection on to a subspace, orthogonal part.
-- The subspace is the span of ws. Assume that ws is an orthonormal list of
-- vectors.
resolve :: RIVS a => a -> [a] -> (a, a)
resolve v ws = (prj, minus v prj)
  where
    prj = foldl plus zero [scale (dot v w) w | w <- ws]


-- ℝ² is a well known real inner-product vector space, and is represented by the
-- R2 type below. In RIVS.hs, it is your turn to make it an instance of RIVS.

data R2 = MkR2 Double Double
    deriving (Eq, Show)

-- ℝ⁵ is also a real inner-product space. Here is a representation using a list,
-- and we assume/assure that the length is 5. This is unsatisfactory because the
-- length is not enforced by the type, but we're just doing a toy exercise. :)
-- Advanced Haskell and some advanced languages have a better way.

data R5L = MkR5L [Double]
    deriving (Eq, Show)