module Data.Separated( Separated , (~>) , single , separatedValues1 , separatedValues , separatedHead , separatedTail , separators ) where import Prelude(Eq, Ord, Show(..), Functor(..), Monad(..), fst, snd, zipWith, (.)) import Data.List.NonEmpty(NonEmpty(..), toList) import Control.Lens(Lens', lens) import Data.Semigroup(Semigroup(..)) -- $setup -- >>> import Prelude(Eq(..), Num(..), String, Int, id) -- >>> import Control.Lens(set, (^.)) -- >>> import Test.QuickCheck(Arbitrary(..)) -- >>> instance (Arbitrary a, Arbitrary s) => Arbitrary (Separated s a) where arbitrary = do a <- arbitrary; x <- arbitrary; return (Separated a x) data Separated s a = Separated a [(s, a)] deriving (Eq, Ord) instance (Show s, Show a) => Show (Separated s a) where show (Separated a x) = '[' : show a <> (x >>= \(s, y) -> show s <> show y) <> "]" -- | Map across a @Separated@ on the element values. -- -- prop> fmap id (x :: Separated Int String) == x -- -- >>> fmap (+1) (single 1) -- [2] -- -- >>> fmap (+1) (set separatedTail [('a', 2), ('b', 3)] (single 1)) -- [2'a'3'b'4] instance Functor (Separated s) where fmap f (Separated a x) = Separated (f a) (fmap (\(s, y) -> (s, f y)) x) -- | Prepend a separator and element to the current tail. -- -- >>> ('b', 9) ~> ('a', 8) ~> single 7 -- [7'b'9'a'8] (~>) :: (s, a) -> Separated s a -> Separated s a e ~> Separated a x = Separated a (e:x) infixr 5 ~> -- | -- -- >>> single 4 -- [4] -- -- prop> single x ^. separatedTail == [] single :: a -> Separated s a single a = Separated a [] -- | Return all element values. -- -- >>> separatedValues1 (single 8) -- 8 :| [] -- -- >>> separatedValues1 (('a', 9) ~> single 8) -- 8 :| [9] -- -- prop> let h :| _ = separatedValues1 (single x) in h == (x :: Int) -- -- prop> let _ :| t = separatedValues1 (e ~> single x) in t == fmap fst [e] separatedValues1 :: Separated s a -> NonEmpty a separatedValues1 (Separated a x) = a :| fmap snd x -- | Return all element values. -- -- >>> separatedValues (single 8) -- [8] -- -- >>> separatedValues (('a', 9) ~> single 8) -- [8,9] -- -- prop> let h : _ = separatedValues (single x) in h == (x :: Int) -- -- prop> let _ : t = separatedValues (e ~> single x) in t == fmap fst [e] separatedValues :: Separated s a -> [a] separatedValues = toList . separatedValues1 -- | A lens on the first element value. -- -- >>> single 7 ^. separatedHead -- 7 -- -- prop> single x ^. separatedHead == (x :: Int) separatedHead :: Lens' (Separated s a) a separatedHead = lens (\(Separated a _) -> a) (\(Separated _ x) a -> Separated a x) -- | A lens on the tail. -- -- >>> single 7 ^. separatedHead -- 7 -- -- prop> (e ~> single x) ^. separatedTail == [e] separatedTail :: Lens' (Separated s a) [(s, a)] separatedTail = lens (\(Separated _ x) -> x) (\(Separated a _) x -> Separated a x) -- | Return all separator values. -- -- >>> separators (('a', 8) ~> single 7) -- "a" -- -- >>> separators (('b', 9) ~> ('a', 8) ~> single 7) -- "ba" -- -- prop> separators (single x) == [] separators :: Separated s a -> [s] separators (Separated _ x) = fmap fst x