{-# LANGUAGE GADTs #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE FlexibleContexts #-} module HZip where import Control.Monad import Base -- * Generic zip class HZip f where hzipM :: Monad m => (forall ix. Ix s ix => s ix -> r ix -> r' ix -> m (r'' ix)) -> f s r ix -> f s r' ix -> m (f s r'' ix) instance HZip (I xi) where hzipM f (I x) (I y) = liftM I (f index x y) instance Eq a => HZip (K a) where hzipM f (K x) (K y) | x == y = return (K x) | otherwise = fail "zip failed in K" instance (HZip a, HZip b) => HZip (a :+: b) where hzipM f (L x) (L y) = liftM L (hzipM f x y) hzipM f (R x) (R y) = liftM R (hzipM f x y) hzipM f _ _ = fail "zip failed" instance (HZip a, HZip b) => HZip (a :*: b) where hzipM f (x1 :*: y1) (x2 :*: y2) = liftM2 (:*:) (hzipM f x1 x2) (hzipM f y1 y2) instance HZip f => HZip (f :>: xi) where hzipM f (Tag x) (Tag y) = liftM Tag (hzipM f x y) -- | Monadic zip but argument is not monadic hzip :: (HZip f, Monad m) => (forall ix. Ix l ix => l ix -> r ix -> s ix -> t ix) -> f l r ix -> f l s ix -> m (f l t ix) hzip f = hzipM (\w x y -> return (f w x y)) -- | Unsafe zip hzip' :: (HZip f) => (forall ix. r ix -> r' ix -> r'' ix) -> f s r ix -> f s r' ix -> f s r'' ix hzip' f a b = case hzip (\ w x y -> f x y) a b of Nothing -> error "generic zip failed" Just res -> res -- | Combine two structures monadically only combine :: (Monad m, HZip f) => (forall ix. Ix s ix => s ix -> r ix -> r' ix -> m ()) -> s ix -> f s r ix -> f s r' ix -> m () combine f l x y = hzipM wrapf x y >> return () where wrapf ix x y = f ix x y >> return (K0 ()) -- | Generic equality geq :: (HZip (PF s), Ix s ix) => s ix -> ix -> ix -> Bool geq ix x y = maybe False (const True) (geq' ix (I0 x) (I0 y)) -- | Monadic generic equality (just for the sake of the monad!) geq' :: (Monad m, HZip (PF s), Ix s ix) => s ix -> I0 ix -> I0 ix -> m () geq' ix (I0 x) (I0 y) = combine geq' ix (from'' x) (from'' y)