module QIO.VecEq where
import QIO.QioSyn
import QIO.Heap
import Control.Applicative (Applicative(..))
import Control.Monad (liftM, ap)
class VecEq v where
vzero :: v x a
(<+>) :: (Eq a, Num x) => v x a -> v x a -> v x a
(<.>) :: (Num x, Eq x) => x -> v x a -> v x a
(<@>) :: (Eq a, Num x) => a -> v x a -> x
fromList :: [(a,x)] -> v x a
toList :: v x a -> [(a,x)]
newtype VecEqL x a = VecEqL {unVecEqL :: [(a,x)]} deriving Show
vEqZero :: VecEqL x a
vEqZero = VecEqL []
add :: (Eq a,Num x) => (a,x) -> VecEqL x a -> VecEqL x a
add (a,x) (VecEqL axs) = VecEqL (addV' axs)
where addV' [] = [(a,x)]
addV' ((by @ (b,y)):bys) | a == b = (b,x+y):bys
| otherwise = by:(addV' bys)
vEqPlus :: (Eq a, Num x) => VecEqL x a -> VecEqL x a -> VecEqL x a
(VecEqL as) `vEqPlus` vbs = foldr add vbs as
vEqTimes :: (Num x, Eq x) => x -> VecEqL x a -> VecEqL x a
l `vEqTimes` (VecEqL bs) | l==0 = VecEqL []
| otherwise = VecEqL (map (\ (b,k) -> (b,l*k)) bs)
vEqAt :: (Eq a, Num x) => a -> VecEqL x a -> x
a `vEqAt` (VecEqL []) = 0
a `vEqAt` (VecEqL ((a',b):abs)) | a == a' = b
| otherwise = a `vEqAt` (VecEqL abs)
instance VecEq VecEqL where
vzero = vEqZero
(<+>) = vEqPlus
(<.>) = vEqTimes
(<@>) = vEqAt
fromList as = VecEqL as
toList (VecEqL as) = as
class EqMonad m where
eqReturn :: Eq a => a -> m a
eqBind :: (Eq a, Eq b) => m a -> (a -> m b) -> m b
instance (VecEq v, Num x, Eq x) => EqMonad (v x) where
eqReturn a = fromList [(a,1)]
eqBind va f = case toList va of
([]) -> vzero
((a,x):[]) -> x <.> f a
((a,x):vas) -> (x <.> f a) <+> ((fromList vas) `eqBind` f)
data AsMonad m a where
Embed :: (EqMonad m, Eq a) => m a -> AsMonad m a
Return :: EqMonad m => a -> AsMonad m a
Bind :: EqMonad m => AsMonad m a -> (a -> AsMonad m b) -> AsMonad m b
instance EqMonad m => Functor (AsMonad m) where
fmap = liftM
instance EqMonad m => Applicative (AsMonad m) where
pure = Return
(<*>) = ap
instance EqMonad m => Monad (AsMonad m) where
return = pure
(>>=) = Bind
unEmbed :: Eq a => AsMonad m a -> m a
unEmbed (Embed m) = m
unEmbed (Return a) = eqReturn a
unEmbed (Bind (Embed m) f) = m `eqBind` (unEmbed.f)
unEmbed (Bind (Return a) f) = unEmbed (f a)
unEmbed (Bind (Bind m f) g) = unEmbed (Bind m (\x -> Bind (f x) g))