Skip to content
Permalink
master
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
-- | This module defines a generic non-empty data structure, which adds an
-- | additional element to any container type.
module Data.NonEmpty
( NonEmpty(..)
, singleton
, (:|)
, foldl1
, fromNonEmpty
, oneOf
, head
, tail
) where
import Prelude
import Control.Alt ((<|>))
import Control.Alternative (class Alternative)
import Control.Plus (class Plus, empty)
import Data.Eq (class Eq1)
import Data.Foldable (class Foldable, foldl, foldr, foldMap)
import Data.FoldableWithIndex (class FoldableWithIndex, foldMapWithIndex, foldlWithIndex, foldrWithIndex)
import Data.FunctorWithIndex (class FunctorWithIndex, mapWithIndex)
import Data.Maybe (Maybe(..), maybe)
import Data.Ord (class Ord1)
import Data.Semigroup.Foldable (class Foldable1)
import Data.Semigroup.Foldable (foldl1) as Foldable1
import Data.Traversable (class Traversable, traverse, sequence)
import Data.TraversableWithIndex (class TraversableWithIndex, traverseWithIndex)
import Data.Tuple (uncurry)
import Data.Unfoldable (class Unfoldable, unfoldr)
import Data.Unfoldable1 (class Unfoldable1)
import Prim.TypeError (class Warn, Text)
-- | A non-empty container of elements of type a.
-- |
-- | ```purescript
-- | import Data.NonEmpty
-- |
-- | nonEmptyArray :: NonEmpty Array Int
-- | nonEmptyArray = NonEmpty 1 [2,3]
-- |
-- | import Data.List(List(..), (:))
-- |
-- | nonEmptyList :: NonEmpty List Int
-- | nonEmptyList = NonEmpty 1 (2 : 3 : Nil)
-- | ```
data NonEmpty f a = NonEmpty a (f a)
-- | An infix synonym for `NonEmpty`.
-- |
-- | ```purescript
-- | nonEmptyArray :: NonEmpty Array Int
-- | nonEmptyArray = 1 :| [2,3]
-- |
-- | nonEmptyList :: NonEmpty List Int
-- | nonEmptyList = 1 :| 2 : 3 : Nil
-- | ```
infixr 5 NonEmpty as :|
-- | Create a non-empty structure with a single value.
-- |
-- | ```purescript
-- | import Prelude
-- |
-- | singleton 1 == 1 :| []
-- | singleton 1 == 1 :| Nil
-- | ```
singleton :: forall f a. Plus f => a -> NonEmpty f a
singleton a = a :| empty
-- | Fold a non-empty structure, collecting results using a binary operation.
-- |
-- | Deprecated, use 'Data.Semigroup.Foldable.foldl1' instead
-- |
-- | ```purescript
-- | foldl1 (+) (1 :| [2, 3]) == 6
-- | ```
foldl1 :: forall f a. Foldable f => Warn (Text "'Data.NonEmpty.foldl1' is deprecated, use 'Data.Semigroup.Foldable.foldl1' instead") => (a -> a -> a) -> NonEmpty f a -> a
foldl1 = Foldable1.foldl1
-- | Apply a function that takes the `first` element and remaining elements
-- | as arguments to a non-empty container.
-- |
-- | For example, return the remaining elements multiplied by the first element:
-- |
-- | ```purescript
-- | fromNonEmpty (\x xs -> map (_ * x) xs) (3 :| [2, 1]) == [6, 3]
-- | ```
fromNonEmpty :: forall f a r. (a -> f a -> r) -> NonEmpty f a -> r
fromNonEmpty f (a :| fa) = a `f` fa
-- | Returns the `alt` (`<|>`) result of:
-- | - The first element lifted to the container of the remaining elements.
-- | - The remaining elements.
-- |
-- | ```purescript
-- | import Data.Maybe(Maybe(..))
-- |
-- | oneOf (1 :| Nothing) == Just 1
-- | oneOf (1 :| Just 2) == Just 1
-- |
-- | oneOf (1 :| [2, 3]) == [1,2,3]
-- | ```
oneOf :: forall f a. Alternative f => NonEmpty f a -> f a
oneOf (a :| fa) = pure a <|> fa
-- | Get the 'first' element of a non-empty container.
-- |
-- | ```purescript
-- | head (1 :| [2, 3]) == 1
-- | ```
head :: forall f a. NonEmpty f a -> a
head (x :| _) = x
-- | Get everything but the 'first' element of a non-empty container.
-- |
-- | ```purescript
-- | tail (1 :| [2, 3]) == [2, 3]
-- | ```
tail :: forall f a. NonEmpty f a -> f a
tail (_ :| xs) = xs
instance showNonEmpty :: (Show a, Show (f a)) => Show (NonEmpty f a) where
show (a :| fa) = "(NonEmpty " <> show a <> " " <> show fa <> ")"
derive instance eqNonEmpty :: (Eq1 f, Eq a) => Eq (NonEmpty f a)
derive instance eq1NonEmpty :: Eq1 f => Eq1 (NonEmpty f)
derive instance ordNonEmpty :: (Ord1 f, Ord a) => Ord (NonEmpty f a)
derive instance ord1NonEmpty :: Ord1 f => Ord1 (NonEmpty f)
derive instance functorNonEmpty :: Functor f => Functor (NonEmpty f)
instance functorWithIndex
:: FunctorWithIndex i f
=> FunctorWithIndex (Maybe i) (NonEmpty f) where
mapWithIndex f (a :| fa) = f Nothing a :| mapWithIndex (f <<< Just) fa
instance foldableNonEmpty :: Foldable f => Foldable (NonEmpty f) where
foldMap f (a :| fa) = f a <> foldMap f fa
foldl f b (a :| fa) = foldl f (f b a) fa
foldr f b (a :| fa) = f a (foldr f b fa)
instance foldableWithIndexNonEmpty
:: (FoldableWithIndex i f)
=> FoldableWithIndex (Maybe i) (NonEmpty f) where
foldMapWithIndex f (a :| fa) = f Nothing a <> foldMapWithIndex (f <<< Just) fa
foldlWithIndex f b (a :| fa) = foldlWithIndex (f <<< Just) (f Nothing b a) fa
foldrWithIndex f b (a :| fa) = f Nothing a (foldrWithIndex (f <<< Just) b fa)
instance traversableNonEmpty :: Traversable f => Traversable (NonEmpty f) where
sequence (a :| fa) = NonEmpty <$> a <*> sequence fa
traverse f (a :| fa) = NonEmpty <$> f a <*> traverse f fa
instance traversableWithIndexNonEmpty
:: (TraversableWithIndex i f)
=> TraversableWithIndex (Maybe i) (NonEmpty f) where
traverseWithIndex f (a :| fa) =
NonEmpty <$> f Nothing a <*> traverseWithIndex (f <<< Just) fa
instance foldable1NonEmpty :: Foldable f => Foldable1 (NonEmpty f) where
foldMap1 f (a :| fa) = foldl (\s a1 -> s <> f a1) (f a) fa
foldr1 f (a :| fa) = maybe a (f a) $ foldr (\a1 -> Just <<< maybe a1 (f a1)) Nothing fa
foldl1 f (a :| fa) = foldl f a fa
instance unfoldable1NonEmpty :: Unfoldable f => Unfoldable1 (NonEmpty f) where
unfoldr1 f b = uncurry (:|) $ unfoldr (map f) <$> f b
-- | This is a lawful `Semigroup` instance that will behave sensibly for common nonempty
-- | containers like lists and arrays. However, it's not guaranteed that `pure` will behave
-- | sensibly alongside `<>` for all types, as we don't have any laws which govern their behavior.
instance semigroupNonEmpty
:: (Applicative f, Semigroup (f a))
=> Semigroup (NonEmpty f a) where
append (a1 :| f1) (a2 :| f2) = a1 :| (f1 <> pure a2 <> f2)