{-# 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 -}