packages feed

descript-lang-0.2.0.0: src/Core/Data/List/NonEmpty.hs

module Core.Data.List.NonEmpty
  ( replicate
  , (|>)
  , (|+)
  , (+|)
  , dropEnd
  , stripPrefix
  , zipPadS
  , zipPadM
  , zipPadLeftS
  , zipPadLeftM
  , zipPadWith
  ) where

import Data.Semigroup as S
import Data.Monoid as M
import qualified Data.List as List (replicate, stripPrefix)
import qualified Core.Data.List as List (
    (|>)
  , zipPadS
  , zipPadM
  , zipPadLeftS
  , zipPadLeftM
  , zipPadWith
  )
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as NonEmpty
import Prelude hiding (replicate)

-- | Creates a list of length @n@, where every element is @x@.
replicate :: Int -> a -> NonEmpty a
replicate n x
  | n < 0 = error "replicate: tried to make NonEmpty with negative elements"
  | n == 0 = error "replicate: tried to make NonEmpty with 0 elements"
  | otherwise = NonEmpty.fromList $ List.replicate n x

-- | Appends an element to the list.
(|>) :: NonEmpty a -> a -> NonEmpty a
(x :| xs) |> y = x :| (xs List.|> y)

-- | Appends a regular list and a non-empty list.
(|+) :: [a] -> NonEmpty a -> NonEmpty a
[] |+ ys = ys
(x : xs) |+ ys = x :| (xs ++ NonEmpty.toList ys)

-- | Appends a non-empty list and a regular list.
(+|) :: NonEmpty a -> [a] -> NonEmpty a
(x :| xs) +| ys = x :| (xs ++ ys)

-- | Removes @n@ elements from the end of the list.
dropEnd :: Int -> NonEmpty a -> [a]
dropEnd n = reverse . NonEmpty.drop n . NonEmpty.reverse

-- | If the second list starts with the first, returns the part after.
-- Otherwise returns 'Nothing'.
stripPrefix :: (Eq a) => NonEmpty a -> NonEmpty a -> Maybe [a]
(x :| xs) `stripPrefix` (y :| ys)
  | x /= y = Nothing
  | otherwise = xs `List.stripPrefix` ys

-- | Zips the lists by appending elements. Won't discard elements at the
-- end of the longer list (so the result is as long as the longer list).
zipPadS :: (Semigroup a) => NonEmpty a -> NonEmpty a -> NonEmpty a
(x :| xs) `zipPadS` (y :| ys) = (x S.<> y) :| (xs `List.zipPadS` ys)

-- | Zips the lists by appending elements. Won't discard elements at the
-- end of the longer list (so the result is as long as the longer list).
zipPadM :: (Monoid a) => NonEmpty a -> NonEmpty a -> NonEmpty a
(x :| xs) `zipPadM` (y :| ys) = (x M.<> y) :| (xs `List.zipPadM` ys)

-- | Zips the lists by \prepending\ elements. The result is as long as
-- the longer list.
zipPadLeftS :: (Semigroup a) => NonEmpty a -> NonEmpty a -> NonEmpty a
(x :| xs) `zipPadLeftS` (y :| ys) = (x S.<> y) :| (xs `List.zipPadLeftS` ys)

-- | Zips the lists by \prepending\ elements. The result is as long as
-- the longer list.
zipPadLeftM :: (Monoid a) => NonEmpty a -> NonEmpty a -> NonEmpty a
(x :| xs) `zipPadLeftM` (y :| ys) = (x M.<> y) :| (xs `List.zipPadLeftM` ys)

-- | Zips the lists, appending 'mempty's to the shorter list instead of
-- discarding elements from the longer list (so the result is as long as
-- the longer list).
zipPadWith :: (Monoid a, Monoid b)
           => (a -> b -> c)
           -> NonEmpty a
           -> NonEmpty b
           -> NonEmpty c
zipPadWith f (x :| xs) (y :| ys) = f x y :| List.zipPadWith f xs ys