-- | This module defines a Vector as a list of pairs. 
-- In the context of QIO, a Vector is the type used to represent a probability
-- distribution.
module QIO.Vec where

import Control.Applicative (Applicative(..))
import Control.Monad       (liftM, ap)

-- | A Vector over types 'x' and 'a' is a wrapper around list of 
-- pairs of 'a' and 'x'.
newtype Vec x a = Vec {unVec :: [(a,x)]} deriving Show

-- | An empty Vector is defined as the empty list
empty :: Vec x a
empty = Vec []
 
-- | The \"probability\" of an object in a Vector, is the sum of all the
-- probabilities associated with that object.
(<@@>) :: (Num x,Eq a) => Vec x a -> a -> x
(Vec ms) <@@> a = foldr (\(b,k) m -> if a == b then m + k else m) 0 ms

-- | A Vector can be multiplied by a scalar, by mapping the multiplcation
-- over each probability in the vector.
(<**>) :: Num x => x -> (Vec x a) -> Vec x a
l <**> (Vec as) = (Vec (map (\ (a,k) -> (a,l*k)) as))

-- | Two Vectors can be added, using list concatenation.
(<++>) :: (Vec x a) -> (Vec x a) -> Vec x a
(Vec as) <++> (Vec bs) = (Vec (as ++ bs))

instance Num n => Functor (Vec n) where
    fmap = liftM
 
instance Num n => Applicative (Vec n)  where
    pure  a = Vec [(a,1)]
    (<*>) = ap

-- | Vectors, over Numeric types, can be defined as a Monad.
instance Num n => Monad (Vec n) where
    return = pure
    (Vec ms) >>= f = Vec [(b,i*j) | (a,i) <- ms, (b,j) <- unVec (f a)]