packages feed

antelude-0.1.0: src/Antelude/Array.hs

{- |
Module      : Antelude.Array
Description : Contains some functions for Arrays, and reexports the Data.Array module.
Maintainer  : dneavesdev@pm.me
-}
module Antelude.Array
    ( -- * Rexports
    module ArrayExport
    -- * New and Reconstructed for safety
    , atIndex
    , enumerate
    , fromList
    , fromNonEmpty
    , map
    , toList
    , toNonEmpty
    , update
    ) where

import safe           Antelude.Bool                  ( and )
import safe           Antelude.Function              ( flip, (|>) )
import safe           Antelude.Internal.TypesClasses
    ( Functor (fmap)
    , List
    , Maybe (..)
    , NonEmpty
    )
import safe qualified Antelude.List.NonEmpty         as NE ( fromList, toList )
import safe           Antelude.Tuple.Pair            ( first, second )

import safe           Data.Array                     as ArrayExport hiding
    ( assocs
    , elems
    , listArray
    , (//)
    , (!)
    )
import safe qualified Data.Array                     as Array

import safe           Prelude                        ( (<=), (>=) )


-- | This is here for parity with Data.List. The definition is just 'fmap' from 'Functor'.
map :: (e -> f) -> Array i e -> Array i f
map = fmap


-- | Convert a 'List' to an 'Array' along with a pair of bounds.
fromList :: (Array.Ix i) => (i, i) -> List a -> Array i a
fromList = Array.listArray


-- | Convert an 'Array' to a 'List'.
toList :: Array i e -> List e
toList = Array.elems


-- | Enumerate an 'Array' into a 'List' of indices i and elements e.
enumerate :: (Array.Ix i) => Array i e -> List (i, e)
enumerate = Array.assocs


-- | Convert a 'NonEmpty' to an 'Array' along with a pair of bounds.
fromNonEmpty :: (Array.Ix i) => (i, i) -> NonEmpty a -> Array i a
fromNonEmpty bound ne = NE.toList ne |> fromList bound

-- | Convert an 'Array' to a 'NonEmpty'.
toNonEmpty :: (Array.Ix i) => Array i a -> Maybe (NonEmpty a)
toNonEmpty arr = toList arr |> NE.fromList


-- | Reconstruct an 'Array' with the given 'List' of indices i and elements e in their designated positions.
update :: (Array.Ix i) => List (i, e) -> Array i e -> Array i e
update = flip (Array.//)


-- | Obtain the element at the given index. 'Nothing' if the index is not valid.
atIndex :: (Array.Ix i) => i -> Array i e -> Maybe e
atIndex idx arr =
  if (idx >= first (Array.bounds arr)) `and` (idx <= second (Array.bounds arr))
    then
      (Array.!) arr idx |> Just
    else
      Nothing