```{-# LANGUAGE RebindableSyntax #-}
{- |
Copyright   :  (c) Henning Thielemann 2004-2005

Maintainer  :  numericprelude@henning-thielemann.de
Stability   :  provisional
Portability :  portable

Abstraction of vectors
-}

module Algebra.Vector where

import qualified Algebra.Ring     as Ring
import qualified Algebra.Additive as Additive

import Algebra.Ring     ((*))
import Algebra.Additive ((+))

import Data.List (zipWith, foldl)
-- import Data.Functor (Functor, fmap)

import Prelude((.), (==), Bool, Functor, fmap)
import qualified Prelude as P

-- Is this right?
infixr 7 *>

{-|
A Module over a ring satisfies:

>   a *> (b + c) === a *> b + a *> c
>   (a * b) *> c === a *> (b *> c)
>   (a + b) *> c === a *> c + b *> c
-}
class C v where
-- duplicate some methods from Additive
-- | zero element of the vector space
zero  :: (Additive.C a) => v a
-- | add and subtract elements
(<+>) :: (Additive.C a) => v a -> v a -> v a
-- | scale a vector by a scalar
(*>)  :: (Ring.C a) => a -> v a -> v a

infixl 6 <+>

{- |
We need a Haskell 98 type class
which provides equality test for Vector type constructors.
-}
class Eq v where
eq :: P.Eq a => v a -> v a -> Bool

infix 4 `eq`

{-* Instances for standard type constructors -}

functorScale :: (Functor v, Ring.C a) => a -> v a -> v a
functorScale = fmap . (*)

instance C [] where
zero  = Additive.zero
(<+>) = (Additive.+)
(*>)  = functorScale

instance C ((->) b) where
zero     = Additive.zero
(<+>)    = (Additive.+)
(*>) s f = (s*) . f

instance Eq [] where
eq = (==)

{-* Related functions -}

{-|
Compute the linear combination of a list of vectors.
-}
linearComb :: (Ring.C a, C v) => [a] -> [v a] -> v a
linearComb c = foldl (<+>) zero . zipWith (*>) c

{- * Properties -}

propCascade :: (C v, Eq v, Ring.C a, P.Eq a) =>
a -> a -> v a -> Bool
propCascade a b c           = (a * b) *> c  `eq`  a *> (b *> c)

propRightDistributive :: (C v, Eq v, Ring.C a, P.Eq a) =>
a -> v a -> v a -> Bool
propRightDistributive a b c =   a *> (b <+> c)  `eq`  a*>b <+> a*>c

propLeftDistributive :: (C v, Eq v, Ring.C a, P.Eq a) =>
a -> a -> v a -> Bool
propLeftDistributive a b c  =   (a+b) *> c  `eq`  a*>c <+> b*>c
```