content: module Data.Index
    ( ZeroBased(..) -- @LAMDERA exposed
    , first
    , second
    , third
    , next
    , toMachine
    , toHuman
    , indexedMap
    , indexedTraverse
    , indexedForA
    , VerifiedList(..)
    , indexedZipWith
    , indexedZipWithA
    )
    where
  
  
  import Control.Monad (liftM)
  import Data.Binary
  
  
  
  -- ZERO BASED
  
  
  newtype ZeroBased = ZeroBased Int
    deriving (Eq, Ord)
  
  
  first :: ZeroBased
  first =
    ZeroBased 0
  
  
  second :: ZeroBased
  second =
    ZeroBased 1
  
  
  third :: ZeroBased
  third =
    ZeroBased 2
  
  
  {-# INLINE next #-}
  next :: ZeroBased -> ZeroBased
  next (ZeroBased i) =
    ZeroBased (i + 1)
  
  
  
  -- DESTRUCT
  
  
  toMachine :: ZeroBased -> Int
  toMachine (ZeroBased index) =
    index
  
  
  toHuman :: ZeroBased -> Int
  toHuman (ZeroBased index) =
    index + 1
  
  
  
  -- INDEXED MAP
  
  
  {-# INLINE indexedMap #-}
  indexedMap :: (ZeroBased -> a -> b) -> [a] -> [b]
  indexedMap func xs =
    zipWith func (map ZeroBased [0 .. length xs]) xs
  
  
  {-# INLINE indexedTraverse #-}
  indexedTraverse :: (Applicative f) => (ZeroBased -> a -> f b) -> [a] -> f [b]
  indexedTraverse func xs =
    sequenceA (indexedMap func xs)
  
  
  {-# INLINE indexedForA #-}
  indexedForA :: (Applicative f) => [a] -> (ZeroBased -> a -> f b) -> f [b]
  indexedForA xs func =
    sequenceA (indexedMap func xs)
  
  
  
  -- VERIFIED/INDEXED ZIP
  
  
  data VerifiedList a
    = LengthMatch [a]
    | LengthMismatch Int Int
  
  
  indexedZipWith :: (ZeroBased -> a -> b -> c) -> [a] -> [b] -> VerifiedList c
  indexedZipWith func listX listY =
    indexedZipWithHelp func 0 listX listY []
  
  
  indexedZipWithHelp :: (ZeroBased -> a -> b -> c) -> Int -> [a] -> [b] -> [c] -> VerifiedList c
  indexedZipWithHelp func index listX listY revListZ =
    case (listX, listY) of
      ([], []) ->
        LengthMatch (reverse revListZ)
  
      (x:xs, y:ys) ->
        indexedZipWithHelp func (index + 1) xs ys $
          func (ZeroBased index) x y : revListZ
  
      (_, _) ->
        LengthMismatch (index + length listX) (index + length listY)
  
  
  indexedZipWithA :: (Applicative f) => (ZeroBased -> a -> b -> f c) -> [a] -> [b] -> f (VerifiedList c)
  indexedZipWithA func listX listY =
    case indexedZipWith func listX listY of
      LengthMatch xs ->
        LengthMatch <$> sequenceA xs
  
      LengthMismatch x y ->
        pure (LengthMismatch x y)
  
  
  
  -- BINARY
  
  
  instance Binary ZeroBased where
    get = liftM ZeroBased get
    put (ZeroBased n) = put n
  