module Data.Zip where

import qualified Data.NonEmpty.Class as C

import qualified Data.Traversable as Trav
import Data.Traversable (Traversable, )
import Control.Applicative (Applicative, pure, (<*>), )
import Control.DeepSeq (NFData, rnf, )


{- |
Wrap a container such that its Applicative instance is based on zip.
-}
newtype T f a = Cons {decons :: f a}

instance Functor f => Functor (T f) where
   fmap f (Cons xs) = Cons $ fmap f xs

instance (C.Zip f, C.Repeat f) => Applicative (T f) where
   pure a = Cons $ C.repeat a
   Cons f <*> Cons x = Cons $ C.zipWith ($) f x


instance (C.NFData f, NFData a) => NFData (T f a) where
   rnf = C.rnf

instance (C.NFData f) => C.NFData (T f) where
   rnf = C.rnf . decons


{- |
Always returns a rectangular list
by clipping all dimensions to the shortest slice.
Be aware that @transpose [] == repeat []@.
-}
transposeClip ::
   (Traversable f, C.Zip g, C.Repeat g) =>
   f (g a) -> g (f a)
transposeClip =
   decons . Trav.sequenceA . fmap Cons