{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
-- | Warning, this is Experimental!
--
-- Data.NonNull attempts to extend the concepts from
-- 'Data.List.NonEmpty' to any 'IsSequence'.
--
-- 'NonNull' is for a sequence with 1 or more elements.
-- 'Stream' is for a 'NonNull' that supports efficient
-- modification of the front of the sequence.
--
-- This code is experimental and likely to change dramatically and future versions.
-- Please send your feedback.
module Data.NonNull where
import Prelude hiding (head, tail, init, last)
import Data.MonoTraversable
import Data.Sequences
import qualified Data.List.NonEmpty as NE
import Data.Semigroup
import qualified Data.Foldable as Foldable
import qualified Data.Vector as V
import qualified Data.Sequence as Seq
import Data.Sequence (Seq)
-- | a NonNull sequence has 1 or more items
class IsSequence seq => NonNull seq where
type NonEmpty seq
nsingleton :: Element seq -> NonEmpty seq
fromNonEmpty :: NE.NonEmpty (Element seq) -> NonEmpty seq
-- | like 'Sequence.filter', but starts with a NonNull
nfilter :: (Element seq -> Bool) -> NonEmpty seq -> seq
-- | like Data.List, but not partial on a NonEmpty
head :: NonEmpty seq -> Element seq
-- | like Data.List, but not partial on a NonEmpty
tail :: NonEmpty seq -> seq
-- | like Data.List, but not partial on a NonEmpty
last :: NonEmpty seq -> Element seq
-- | like Data.List, but not partial on a NonEmpty
init :: NonEmpty seq -> seq
-- | NonNull list reuses 'Data.List.NonEmpty'
instance NonNull [a] where
type NonEmpty [a] = NE.NonEmpty a
nsingleton = (NE.:| [])
fromNonEmpty = id
nfilter = NE.filter
head = NE.head
tail = NE.tail
last = NE.last
init = NE.init
-- | a wrapper indicating there are 1 or more elements
-- unwrap with toSequence
data NotEmpty seq = NotEmpty { toSequence :: seq }
instance NonNull (Seq.Seq a) where
type NonEmpty (Seq a) = NotEmpty (Seq a)
nsingleton = NotEmpty . Seq.singleton
fromNonEmpty = NotEmpty . Seq.fromList . NE.toList
nfilter f = Seq.filter f . toSequence
head = flip Seq.index 1 . toSequence
last (NotEmpty seq) = Seq.index seq (Seq.length seq - 1)
tail = Seq.drop 1 . toSequence
init (NotEmpty seq) = Seq.take (Seq.length seq - 1) seq
instance NonNull (V.Vector a) where
type NonEmpty (V.Vector a) = NotEmpty (V.Vector a)
nsingleton = NotEmpty . V.singleton
fromNonEmpty = NotEmpty . V.fromList . NE.toList
nfilter f = V.filter f . toSequence
head = V.head . toSequence
tail = V.tail . toSequence
last = V.last . toSequence
init = V.init . toSequence
infixr 5 .:, <|
-- | a stream is a NonNull that supports efficient modification of the front of the sequence
class NonNull seq => Stream seq where
-- | Prepend an element, creating a NonEmpty
-- Data.List.NonEmpty gets to use the (:|) operator,
-- but this can't because it is not a data constructor
(.:) :: Element seq -> seq -> NonEmpty seq
-- | Prepend an element to a NonEmpty
(<|) :: Element seq -> NonEmpty seq -> NonEmpty seq
instance Stream [a] where
(.:) = (NE.:|)
(<|) = (NE.<|)
instance Stream (Seq a) where
(.:) x = NotEmpty . (x Seq.<|)
(<|) x = NotEmpty . (x Seq.<|) . toSequence
{-
class (NonNull seq, Ord (Element seq)) => OrdNonNull seq where
-- | like Data.List, but not partial on a NonEmpty
maximum :: NonEmpty seq -> Element seq
-- | like Data.List, but not partial on a NonEmpty
minimum :: NonEmpty seq -> Element seq
-- | like Data.List, but not partial on a NonEmpty
maximumBy :: (Element seq -> Element seq -> Ordering) -> NonEmpty seq -> Element seq
-- | like Data.List, but not partial on a NonEmpty
minimumBy :: (Element seq -> Element seq -> Ordering) -> NonEmpty seq -> Element seq
instance Ord a => OrdNonNull [a] where
maximum = Foldable.maximum
minimum = Foldable.minimum
maximumBy = Foldable.maximumBy
minimumBy = Foldable.minimumBy
instance Ord a => OrdNonNull (Seq a) where
maximum = Foldable.maximum
minimum = Foldable.minimum
maximumBy = Foldable.maximumBy
minimumBy = Foldable.minimumBy
instance Ord a => OrdNonNull (V.Vector a) where
maximum = Foldable.maximum
minimum = Foldable.minimum
maximumBy = Foldable.maximumBy
minimumBy = Foldable.minimumBy
-}