{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE MultiParamTypeClasses #-} module Data.Separated.FlipSeparated( FlipSeparated , flipSeparated , flipSeparated1 , fempty ) where import Control.Applicative(Applicative(pure, (<*>))) import Control.Category(Category(id, (.))) import Control.Lens.Getter((^.)) import Control.Lens.Iso(Iso, iso) import Control.Lens.Review((#)) import Data.Bifunctor(Bifunctor(bimap)) import Data.Eq(Eq) import Data.Functor(Functor(fmap)) import Data.Functor.Apply(Apply((<.>))) import Data.List(zipWith) import Data.Monoid(Monoid(mappend, mempty)) import Data.Ord(Ord) import Data.Semigroup(Semigroup((<>))) import Data.Separated.FlipSeparatedCons(FlipSeparatedCons(FlipSeparatedConsF, FlipSeparatedConsG, (+.))) import Data.Separated.Separated(Separated, Separated1, separated, separated1, separatedSwap, empty) import Data.Separated.SeparatedCons((+:)) import Prelude(Show(show)) -- $setup -- >>> :set -XNoImplicitPrelude -- >>> import Control.Monad(Monad(return)) -- >>> import Data.Char(toUpper) -- >>> import Data.Int(Int) -- >>> import Data.Eq(Eq((==))) -- >>> import Data.List(reverse, drop) -- >>> import Data.Separated.Separated(empty, single) -- >>> import Data.String(String) -- >>> import Prelude(Num((+))) -- >>> import Test.QuickCheck(Arbitrary(..)) -- >>> instance (Arbitrary s, Arbitrary a) => Arbitrary (Separated s a) where arbitrary = fmap (^. separated) arbitrary -- >>> instance (Arbitrary a, Arbitrary s) => Arbitrary (Separated1 s a) where arbitrary = do a <- arbitrary; x <- arbitrary; return ((a, x) ^. separated1) -- >>> instance (Arbitrary s, Arbitrary a) => Arbitrary (FlipSeparated a s) where arbitrary = fmap FlipSeparated arbitrary -- >>> instance (Arbitrary a, Arbitrary s) => Arbitrary (FlipSeparated1 s a) where arbitrary = do a <- arbitrary; return (FlipSeparated1 a) newtype FlipSeparated a s = FlipSeparated (Separated s a) deriving (Eq, Ord) instance Bifunctor FlipSeparated where bimap f g (FlipSeparated x) = FlipSeparated (bimap g f x) -- | Map across a @FlipSeparated@ on the separator values. -- -- prop> fmap id (x :: FlipSeparated Int String) == x -- -- prop> fmap (+1) (a +. b +. fempty) == (1+a) +. b +. fempty instance Functor (FlipSeparated a) where fmap = bimap id -- | Applies functions with separator values, using a zipping operation, -- appending elements. -- -- >>> (fempty :: FlipSeparated [Int] (String -> [String])) <.> fempty -- [] -- -- >>> (\s -> [s, reverse s, drop 1 s]) +. [1,2] +. fempty <.> "abc" +. [3,4,5] +. fempty -- [["abc","cba","bc"],[1,2,3,4,5]] instance Semigroup a => Apply (FlipSeparated a) where FlipSeparated x <.> FlipSeparated y = FlipSeparated (separatedSwap # (x ^. separatedSwap <.> y ^. separatedSwap)) -- | Applies functions with separator values, using a zipping operation, appending -- elements. The identity operation is an infinite list of the empty element -- and the given separator value. -- -- >>> (fempty :: FlipSeparated [Int] (String -> [String])) <*> fempty -- [] -- -- >>> (\s -> [s, reverse s, drop 1 s]) +. [1,2] +. fempty <*> "abc" +. [3,4,5] +. fempty -- [["abc","cba","bc"],[1,2,3,4,5]] instance Monoid s => Applicative (FlipSeparated s) where FlipSeparated x <*> FlipSeparated y = FlipSeparated (separatedSwap # (x ^. separatedSwap <*> y ^. separatedSwap)) pure = FlipSeparated . (#) separatedSwap . pure instance (Show s, Show a) => Show (FlipSeparated s a) where show (FlipSeparated x) = show x instance Semigroup (FlipSeparated s a) where FlipSeparated x <> FlipSeparated y = FlipSeparated (x <> y) instance Monoid (FlipSeparated s a) where mappend = (<>) mempty = FlipSeparated mempty instance FlipSeparatedCons FlipSeparated1 FlipSeparated where type FlipSeparatedConsF FlipSeparated = FlipSeparated1 type FlipSeparatedConsG FlipSeparated1 = FlipSeparated s +. p = (s +: flipSeparated1 # p) ^. flipSeparated -- | The isomorphism to a @Separator@. -- -- >>> empty ^. flipSeparated -- [] -- -- >>> ('x' +: 6 +: empty) ^. flipSeparated -- ['x',6] -- -- >>> [] ^. separated . flipSeparated -- [] -- -- >>> [(6, [])] ^. separated . flipSeparated -- [6,[]] flipSeparated :: Iso (Separated s a) (Separated t b) (FlipSeparated a s) (FlipSeparated b t) flipSeparated = iso FlipSeparated (\(FlipSeparated x) -> x) fempty :: FlipSeparated a s fempty = FlipSeparated empty newtype FlipSeparated1 s a = FlipSeparated1 (Separated1 a s) instance Bifunctor FlipSeparated1 where bimap f g (FlipSeparated1 x) = FlipSeparated1 (bimap g f x) instance Functor (FlipSeparated1 a) where fmap = bimap id -- | Applies functions with element values, using a zipping operation, -- appending separators. -- -- >>> fmap toUpper +. [3,4] +. reverse +. fempty <.> "abc" +. [5,6,7] +. "def" +. fempty -- ["ABC",[3,4,5,6,7],"fed"] instance Semigroup a => Apply (FlipSeparated1 a) where (<.>) = flipSeparated1Ap (<>) -- | Applies functions with element values, using a zipping operation, -- appending separators. The identity operation is an infinite list of the empty -- separator and the given element value. -- -- >>> fmap toUpper +. [3,4] +. reverse +. fempty <*> "abc" +. [5,6,7] +. "def" +. fempty -- ["ABC",[3,4,5,6,7],"fed"] instance Monoid s => Applicative (FlipSeparated1 s) where (<*>) = flipSeparated1Ap mappend pure a = FlipSeparated1 ((a, pure a) ^. separated1) instance (Show s, Show a) => Show (FlipSeparated1 s a) where show (FlipSeparated1 x) = show x -- | The isomorphism to a @Separated1@. -- -- >>> single 6 ^. flipSeparated1 -- [6] -- -- >>> (5 +: 'x' +: single 6) ^. flipSeparated1 -- [5,'x',6] -- -- >>> (6 +: empty) ^. flipSeparated1 -- [6] -- -- >>> (5 +: 'x' +: 6 +: empty) ^. flipSeparated1 -- [5,'x',6] flipSeparated1 :: Iso (Separated1 a s) (Separated1 b t) (FlipSeparated1 s a) (FlipSeparated1 t b) flipSeparated1 = iso FlipSeparated1 (\(FlipSeparated1 x) -> x) instance FlipSeparatedCons FlipSeparated FlipSeparated1 where type FlipSeparatedConsF FlipSeparated1 = FlipSeparated type FlipSeparatedConsG FlipSeparated = FlipSeparated1 a +. p = (a +: flipSeparated # p) ^. flipSeparated1 ---- flipSeparated1Ap :: (s -> s -> s) -> FlipSeparated1 s (a -> b) -> FlipSeparated1 s a -> FlipSeparated1 s b flipSeparated1Ap op (FlipSeparated1 x) (FlipSeparated1 y) = let (f, fs) = separated1 # x (a, as) = separated1 # y in FlipSeparated1 ((f a, zipWith (\(s, f') (t, a') -> (s `op` t, f' a')) (separated # fs) (separated # as) ^. separated) ^. separated1)