pinchot-0.18.2.0: lib/Pinchot/NonEmpty.hs
{-# OPTIONS_HADDOCK not-home #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
{-# LANGUAGE DeriveDataTypeable #-}
-- | Sequences that always contain at least one element.
module Pinchot.NonEmpty where
import Control.Monad (join, ap)
import Data.Data (Data)
import Data.Semigroup (Semigroup((<>)))
import Data.Sequence (Seq, (<|))
import qualified Data.Sequence as Seq
import qualified Control.Lens as Lens
-- | A non-empty sequence.
data NonEmpty a = NonEmpty
{ _front :: a
-- ^ The first item
, _rest :: Seq a
-- ^ All remaining items
} deriving (Eq, Ord, Show, Data, Functor, Foldable, Traversable)
instance Semigroup (NonEmpty a) where
(NonEmpty a1 as) <> (NonEmpty b1 bs)
= NonEmpty a1 (as <> (b1 <| bs))
Lens.makeLenses ''NonEmpty
-- | Convert a 'NonEmpty' to a 'Seq'.
flatten :: NonEmpty a -> Seq a
flatten (NonEmpty a as) = a <| as
instance Monad NonEmpty where
return a = NonEmpty a Seq.empty
NonEmpty a as >>= f = NonEmpty (_front r1) rs
where
r1 = f a
rs = _rest r1 `mappend` rss
rss = join . fmap flatten . fmap f $ as
instance Applicative NonEmpty where
pure = return
(<*>) = ap
-- | Converts a non-empty 'Seq' to a 'NonEmpty'; 'Nothing' if the
-- 'Seq' is empty.
seqToNonEmpty :: Seq a -> Maybe (NonEmpty a)
seqToNonEmpty = fmap (uncurry NonEmpty) . Lens.uncons
-- | Prepends a 'Seq' to a 'NonEmpty'.
prependSeq :: Seq a -> NonEmpty a -> NonEmpty a
prependSeq sq (NonEmpty a as) = case Lens.uncons sq of
Nothing -> NonEmpty a as
Just (l, ls) -> NonEmpty l (ls `mappend` (a <| as))
-- | Appends a 'Seq' to a 'NonEmpty'.
appendSeq :: NonEmpty a -> Seq a -> NonEmpty a
appendSeq (NonEmpty a as) sq = NonEmpty a (as `mappend` sq)
-- | Associative operation that appends to 'NonEmpty'.
append :: NonEmpty a -> NonEmpty a -> NonEmpty a
append (NonEmpty l1 ls) (NonEmpty r1 rs)
= NonEmpty l1 (ls `mappend` (r1 <| rs))
-- | Place a single item at the head of the 'NonEmpty'.
singleton :: a -> NonEmpty a
singleton a = NonEmpty a Seq.empty