separated 0.1.2 → 0.2.0
raw patch · 7 files changed
+885/−497 lines, 7 filesdep −papadep ~basenew-uploader
Dependencies removed: papa
Dependency ranges changed: base
Files
- LICENCE +31/−0
- changelog +5/−0
- etc/LICENCE +0/−27
- separated.cabal +6/−6
- src/Data/Separated.hs +843/−3
- src/Data/Separated/Separated.hs +0/−443
- src/Data/Separated/SeparatedCons.hs +0/−18
+ LICENCE view
@@ -0,0 +1,31 @@+Copyright (c) 2017, Commonwealth Scientific and Industrial Research Organisation+(CSIRO) ABN 41 687 119 230.++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of QFPL nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
changelog view
@@ -1,3 +1,8 @@+0.2.0++* Refactoring with lots of changes to data types.+* Introduce nix for building.+ 0.1.2 * Add instance of `Wrapped` and `Swapped`.
− etc/LICENCE
@@ -1,27 +0,0 @@-Copyright 2013-2014 Tony Morris--All rights reserved.--Redistribution and use in source and binary forms, with or without-modification, are permitted provided that the following conditions-are met:-1. Redistributions of source code must retain the above copyright- notice, this list of conditions and the following disclaimer.-2. Redistributions in binary form must reproduce the above copyright- notice, this list of conditions and the following disclaimer in the- documentation and/or other materials provided with the distribution.-3. Neither the name of the author nor the names of his contributors- may be used to endorse or promote products derived from this software- without specific prior written permission.--THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE-ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF-SUCH DAMAGE.
separated.cabal view
@@ -1,13 +1,16 @@ name: separated-version: 0.1.2+version: 0.2.0 license: BSD3-license-File: etc/LICENCE+license-File: LICENCE author: Tony Morris <ʇǝu˙sıɹɹoɯʇ@ןןǝʞsɐɥ> maintainer: Tony Morris copyright: Copyright (c) 2016, Commonwealth Scientific and Industrial Research Organisation (CSIRO) ABN 41 687 119 230. synopsis: A data type with elements separated by values category: Data-description: A data type with elements separated by values+description: + <<http://i.imgur.com/0h9dFhl.png>>+ .+ A data type with elements separated by values homepage: https://github.com/data61/separated bug-reports: https://github.com/data61/separated/issues cabal-version: >= 1.10@@ -31,7 +34,6 @@ , semigroups >= 0.9 , semigroupoids >= 4.0 , bifunctors >= 4.0- , papa ghc-options: -Wall@@ -44,8 +46,6 @@ exposed-modules: Data.Separated- Data.Separated.Separated- Data.Separated.SeparatedCons test-suite doctests type:
src/Data/Separated.hs view
@@ -1,8 +1,848 @@ {-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE RankNTypes #-} module Data.Separated(- module S+-- * Data types+ Separated(..)+, Separated1(..)+, Pesarated(..)+, Pesarated1(..)+-- * Iso+, separated+, separated1+, pesarated+, pesarated1+-- * Viewing+, HasHead(..)+, HasTail(..)+-- * Constructing+, Separated1Single(..)+, Pesarated1Single(..)+, Construct(..)+, SeparatedCons(..)+, PesaratedCons(..)+-- * Appending+, Appends(..)+-- * Alternating+, separatedBy+, separatedBy1+, pesaratedBy+, pesaratedBy1 ) where -import Data.Separated.Separated as S-import Data.Separated.SeparatedCons as S+import Control.Applicative(Applicative((<*>), pure), Alternative(many))+import Control.Category(Category((.), id))+import Control.Lens(Swapped(swapped), Iso, Lens, iso, from, (#), (^.), _1, _2, makeWrapped, _Wrapped)+import Data.Bifoldable(Bifoldable(bifoldr))+import Data.Bifunctor(Bifunctor(bimap), first)+import Data.Bitraversable(Bitraversable(bitraverse))+import Data.Eq(Eq)+import Data.Foldable(foldr)+import Data.Functor(Functor(fmap), (<$>))+import Data.Functor.Apply as Apply(Apply((<.>)))+import Data.List(intercalate, zipWith, repeat)+import Data.Monoid(Monoid(mappend, mempty))+import Data.Ord(Ord)+import Data.Semigroup as Semigroup(Semigroup((<>)))+import Data.String(String)+import Data.Traversable(traverse)+import Data.Tuple(uncurry)+import Prelude(Show(show))++-- $setup+-- >>> :set -XNoImplicitPrelude+-- >>> :set -XFlexibleContexts+-- >>> import Control.Lens(set)+-- >>> import Control.Monad(return)+-- >>> import Data.Char(toUpper)+-- >>> import Data.Either(isLeft)+-- >>> import Prelude hiding (id, (.))+-- >>> import Text.Parsec(parse, char, digit)+-- >>> 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 (Pesarated s a) where arbitrary = fmap (^. pesarated) arbitrary+-- >>> instance (Arbitrary s, Arbitrary a) => Arbitrary (Pesarated1 s a) where arbitrary = fmap (^. pesarated1) arbitrary+-- >>> let emptySeparated :: Separated s a; emptySeparated = empty+-- >>> let emptyPesarated :: Pesarated s a; emptyPesarated = empty++-- | A list of pairs of separator and value. Separated by @a@ in values @b@.+-- There are an even number of separators as there are values.+newtype Separated a b =+ Separated [(a, b)]+ deriving (Eq, Ord)++-- | A list of pairs of separator and value. Separated by @a@ in values @b@.+-- There is one more value than there are separators.+data Separated1 b a =+ Separated1 b (Separated a b)+ deriving (Eq, Ord)++-- | The @Separated@ type constructor, flipped.+newtype Pesarated b a =+ Pesarated (Separated a b)+ deriving (Eq, Ord)++-- | The @Separated1@ type constructor, flipped.+newtype Pesarated1 a b =+ Pesarated1 (Separated1 b a)+ deriving (Eq, Ord)++-- | The isomorphism to a list of pairs of element and separator values.+--+-- >>> separated # emptySeparated+-- []+--+-- >>> separated # ('x' +: 6 +: emptySeparated)+-- [('x',6)]+--+-- >>> [] ^. separated+-- []+--+-- >>> [(6, [])] ^. separated+-- [6,[]]+separated ::+ Iso [(a, b)] [(c, d)] (Separated a b) (Separated c d)+separated =+ from _Wrapped++-- | The isomorphism to element values interspersed with a separator.+--+-- >>> separated1 # (singleSeparated 6)+-- (6,[])+--+-- >>> separated1 # (5 +: 'x' +: singleSeparated 6)+-- (5,['x',6])+--+-- >>> (6, emptySeparated) ^. separated1+-- [6]+--+-- >>> (5, 'x' +- 6) ^. separated1+-- [5,'x',6]+separated1 ::+ Iso (a, Separated s a) (b, Separated t b) (Separated1 a s) (Separated1 b t)+separated1 =+ iso (uncurry Separated1) (\(Separated1 a x) -> (a, x))++-- | The isomorphism to element values interspersed with a separator.+--+-- >>> pesarated # emptyPesarated+-- []+--+-- >>> ('a', 'x' +- 6) ^. pesarated1+-- ['a',6,'x']+--+-- >>> ('x' -: 6 -: emptyPesarated)+-- ['x',6]+pesarated ::+ Iso [(a, b)] [(c, d)] (Pesarated b a) (Pesarated d c)+pesarated =+ separated . from _Wrapped++-- | The isomorphism to element values interspersed with a separator.+--+-- >>> pesarated1 # singlePesarated 6+-- (6,[])+--+-- >>> pesarated1 # (8 -: 'x' -: singlePesarated 6)+-- (8,['x',6])+--+-- >>> (6, empty) ^. pesarated1+-- [6]+--+-- >>> (5, 'x' -+ 6) ^. pesarated1+-- [5,'x',6]+pesarated1 ::+ Iso (a, Pesarated a s) (b, Pesarated b t) (Pesarated1 s a) (Pesarated1 t b)+pesarated1 =+ iso+ (\(a, Pesarated x) -> Pesarated1 (Separated1 a x))+ (\(Pesarated1 (Separated1 a x)) -> (a, Pesarated x))++-- | Structures that have a head element.+class HasHead s t a b | s -> a, t -> b, s b -> t, t a -> s where+ headL ::+ Lens s t a b++-- | A lens on the first element value.+--+-- >>> (singleSeparated 7 :: Separated1 Int Char) ^. headL+-- 7+--+-- prop> (singleSeparated x :: Separated1 Int Char) ^. headL == (x :: Int)+instance HasHead (Separated1 a t) (Separated1 a t) a a where+ headL =+ from separated1 . _1++-- | A lens on the first element value.+--+-- >>> (singlePesarated 7 :: Pesarated1 Char Int) ^. headL+-- 7+--+-- prop> (singlePesarated x :: Pesarated1 Char Int) ^. headL == (x :: Int)+instance HasHead (Pesarated1 a t) (Pesarated1 a t) t t where+ headL =+ _Wrapped . headL++-- | Structures that have a tail.+class HasTail s t a b | s -> a, t -> b, s b -> t, t a -> s where+ tailL ::+ Lens s t a b++-- | A lens on the tail.+--+-- prop> (d +: e +: (singleSeparated x :: Separated1 Int Char)) ^. tailL == e +: x +: emptySeparated+instance HasTail (Separated1 a s) (Separated1 a t) (Separated s a) (Separated t a) where+ tailL =+ from separated1 . _2++-- | A lens on the tail.+--+-- prop> (d -: e -: (singlePesarated x :: Pesarated1 Char Int)) ^. tailL == e -: x -: emptyPesarated+instance HasTail (Pesarated1 a s) (Pesarated1 b s) (Pesarated s a) (Pesarated s b) where+ tailL =+ _Wrapped . tailL . from _Wrapped++-- | Construct a single separated value.+class Separated1Single f where+ singleSeparated ::+ a+ -> f a s++-- | Zero element values interspersed with one element.+--+-- >>> (singleSeparated 4 :: Separated1 Int Char)+-- [4]+--+-- prop> (singleSeparated x :: Separated1 Int Char) ^. tailL == emptySeparated+instance Separated1Single Separated1 where+ singleSeparated a =+ Separated1 a mempty++class Pesarated1Single f where+ singlePesarated ::+ a+ -> f s a++-- | Zero element values interspersed with one element.+--+-- >>> (singlePesarated 4 :: Pesarated1 Char Int)+-- [4]+--+-- prop> (singlePesarated x :: Pesarated1 Int Char) ^. tailL == emptyPesarated+instance Pesarated1Single Pesarated1 where+ singlePesarated a =+ Pesarated1 (Separated1 a mempty)++-- | Construction of separated values.+class Construct f where+ (+-) ::+ s+ -> a+ -> f s a+ (-+) ::+ s+ -> a+ -> f a s+ empty ::+ f s a+ sprinkle ::+ s+ -> [a]+ -> f s a++infixl 9 +-++-- | One element and one separator.+--+-- >>> (7 +- "abc") :: Separated Int String+-- [7,"abc"]+--+-- >>> 7 +: "abc" +: (8 +- "def") :: Separated Int String +-- [7,"abc",8,"def"]+instance Construct Separated where+ s +- a =+ Separated [(s, a)]+ s -+ a =+ swapped # (s +- a)+ empty =+ Separated mempty+ sprinkle s as =+ Separated+ ((,) s <$> as)++-- | One element and one separator.+--+-- >>> (7 -+ "abc") :: Pesarated String Int+-- [7,"abc"]+--+-- >>> 7 -: "abc" -: (8 -+ "def") :: Pesarated String Int+-- [7,"abc",8,"def"]+instance Construct Pesarated where+ s +- a =+ swapped . _Wrapped # (s +- a)+ s -+ a =+ _Wrapped # (s +- a)+ empty =+ Pesarated empty+ sprinkle s as =+ Pesarated+ (swapped # sprinkle s as)++-- | Prepend a value to a separated-like structure.+class (f ~ SeparatedConsF g, g ~ SeparatedConsG f) => SeparatedCons f g where+ type SeparatedConsF g :: * -> * -> *+ type SeparatedConsG f :: * -> * -> *+ (+:) ::+ a+ -> f b a+ -> g a b+ +infixr 5 +:++instance SeparatedCons Separated1 Separated where+ type SeparatedConsF Separated = Separated1+ type SeparatedConsG Separated1 = Separated+ s +: Separated1 a (Separated x) =+ Separated ((s, a) : x)++instance SeparatedCons Separated Separated1 where+ type SeparatedConsF Separated1 = Separated+ type SeparatedConsG Separated = Separated1+ (+:) =+ Separated1++-- | Prepend a value to a separated-like structure.+class (f ~ PesaratedConsF g, g ~ PesaratedConsG f) => PesaratedCons f g where+ type PesaratedConsF g :: * -> * -> *+ type PesaratedConsG f :: * -> * -> *+ (-:) ::+ b+ -> f b a+ -> g a b+ +infixr 5 -:++instance PesaratedCons Pesarated Pesarated1 where+ type PesaratedConsF Pesarated1 = Pesarated+ type PesaratedConsG Pesarated = Pesarated1+ b -: (Pesarated x) =+ Pesarated1+ (b +: x)++instance PesaratedCons Pesarated1 Pesarated where+ type PesaratedConsF Pesarated = Pesarated1+ type PesaratedConsG Pesarated1 = Pesarated+ b -: (Pesarated1 x) =+ Pesarated (b +: x)++-- | Append two to make one.+class Appends a b c | a b -> c where+ (<++>) ::+ a+ -> b+ -> c++infixr 5 <++>++-- | Append two lists of separated values to produce a list of pairs of separator and element values.+--+-- >>> (singleSeparated 7 :: Separated1 Int Char) <++> (singleSeparated 'a' :: Separated1 Char Int)+-- [7,'a']+--+-- 'a' +: (singleSeparated 7 :: Separated1 Int Char) <++> (singleSeparated 'b' :: Separated1 Char Int)+-- ['a',7,'b']+--+-- prop> a +: (b :: Separated Int Int) == a +: b -- (a +: (b <++> c)) == ((a +: b) <++> c)+instance Appends (Separated1 s a) (Separated1 a s) (Separated s a) where+ Separated1 s x <++> Separated1 t (Separated y) =+ let (q, r') = (s, x) ^. separated1 . shift+ in Separated (q <> ((r', t) : y))++-- | Append element values interspersed with a separator to a list of pairs of separator and element values.+--+-- >>> (emptySeparated :: Separated Int Char) <++> (singleSeparated 7 :: Separated1 Int Char)+-- [7]+--+-- >>> (emptySeparated :: Separated Int Char) <++> 6 +: 'x' +: (singleSeparated 7 :: Separated1 Int Char)+-- [6,'x',7]+--+-- >>> 'w' +: (emptySeparated :: Separated Int Char) <++> 6 +: 'x' +: (singleSeparated 7 :: Separated1 Int Char)+-- ['w',6,'x',7]+instance Appends (Separated s a) (Separated1 s a) (Separated1 s a) where+ Separated x <++> Separated1 t y =+ let (z, w') = separated1 . shift # (x, t)+ in Separated1 z (w' <> y)++-- | Append a list of pairs of separator and element values to element values interspersed with a separator.+--+-- >>> (singleSeparated 7 :: Separated1 Int Char) <++> (emptySeparated :: Separated Char Int)+-- [7]+--+-- >>> (singleSeparated 6 :: Separated1 Int Char) <++> 'x' +: 7 +: (emptySeparated :: Separated Char Int)+-- [6,'x',7]+--+-- >>> 'w' +: (singleSeparated 6 :: Separated1 Int Char) <++> 'x' +: 7 +: (emptySeparated :: Separated Char Int)+-- ['w',6,'x',7]+instance Appends (Separated1 a s) (Separated s a) (Separated1 a s) where+ Separated1 a x <++> y =+ Separated1 a (x <> y)++-- | Alternate separated values e.g. `f ~ Parser`.+--+-- >>> parse (separatedBy (char ',') digit) "test" ""+-- Right []+--+-- >>> isLeft (parse (separatedBy (char ',') digit) "test" ",")+-- True+--+-- >>> parse (separatedBy (char ',') digit) "test" ",1"+-- Right [',','1']+--+-- >>> isLeft (parse (separatedBy (char ',') digit) "test" ",1,")+-- True+--+-- >>> parse (separatedBy (char ',') digit) "test" ",1,2,3,4,5"+-- Right [',','1',',','2',',','3',',','4',',','5']+separatedBy ::+ Alternative f =>+ f a+ -> f b+ -> f (Separated a b)+separatedBy a b =+ Separated <$>+ many+ ((,) <$> a <*> b)++-- | Alternate separated values e.g. `f ~ Parser`.+--+-- >>> isLeft (parse (separatedBy1 (char ',') digit) "test" "")+-- True+--+-- >>> parse (separatedBy1 (char ',') digit) "test" ","+-- Right [',']+--+-- >>> isLeft (parse (separatedBy1 (char ',') digit) "test" ",1")+-- True+--+-- >>> parse (separatedBy1 (char ',') digit) "test" ",1,"+-- Right [',','1',',']+--+-- >>> parse (separatedBy1 (char ',') digit) "test" ",1,2,3,4,5,"+-- Right [',','1',',','2',',','3',',','4',',','5',',']+separatedBy1 ::+ Alternative f =>+ f b+ -> f a+ -> f (Separated1 b a)+separatedBy1 b a =+ Separated1 <$> b <*> separatedBy a b++-- | Alternate separated values e.g. `f ~ Parser`.+--+-- >>> parse (pesaratedBy (char ',') digit) "test" ""+-- Right []+--+-- >>> isLeft (parse (pesaratedBy (char ',') digit) "test" ",")+-- True+--+-- >>> parse (separatedBy (char ',') digit) "test" ",1"+-- Right [',','1']+--+-- >>> isLeft (parse (pesaratedBy (char ',') digit) "test" ",1,")+-- True+--+-- >>> parse (pesaratedBy (char ',') digit) "test" ",1,2,3,4,5"+-- Right [',','1',',','2',',','3',',','4',',','5']+pesaratedBy ::+ Alternative f =>+ f a+ -> f b+ -> f (Pesarated b a)+pesaratedBy a b =+ Pesarated <$> separatedBy a b++-- | Alternate separated values e.g. `f ~ Parser`.+--+-- >>> isLeft (parse (pesaratedBy1 (char ',') digit) "test" "")+-- True+--+-- >>> parse (pesaratedBy1 (char ',') digit) "test" ","+-- Right [',']+--+-- >>> isLeft (parse (pesaratedBy1 (char ',') digit) "test" ",1")+-- True+--+-- >>> parse (pesaratedBy1 (char ',') digit) "test" ",1,"+-- Right [',','1',',']+--+-- >>> parse (pesaratedBy1 (char ',') digit) "test" ",1,2,3,4,5,"+-- Right [',','1',',','2',',','3',',','4',',','5',',']+pesaratedBy1 ::+ Alternative f =>+ f b+ -> f a+ -> f (Pesarated1 a b)+pesaratedBy1 b a =+ Pesarated1 <$> separatedBy1 b a++-- | The isomorphism that swaps elements with their separators.+--+-- >>> swapped # emptySeparated+-- []+--+-- >>> swapped # ('x' +: 6 +: emptySeparated)+-- [6,'x']+--+-- >>> emptySeparated ^. swapped+-- []+--+-- >>> ('x' +: 6 +: emptySeparated) ^. swapped+-- [6,'x']+instance Swapped Separated where+ swapped =+ let swap = (\(Separated x) -> Separated (fmap (\(a, b) -> (b, a)) x))+ in iso swap swap++instance Bifunctor Separated where+ bimap f g (Separated x) =+ Separated (fmap (bimap f g) x)++instance Bifoldable Separated where+ bifoldr f g z (Separated x) =+ foldr (\(a, b) -> f a . g b) z x++instance Bitraversable Separated where+ bitraverse f g (Separated x) =+ Separated <$> traverse (\(a, b) -> (,) <$> f a <*> g b) x++-- | Map across a @Separated@ on the element values.+--+-- prop> fmap id (x :: Separated Int String) == x+--+-- prop> \a b -> fmap (+1) (a +: b +: emptySeparated) == a +: (1+b) +: emptySeparated+instance Functor (Separated a) where+ fmap =+ bimap id++-- | Applies functions with element values, using a zipping operation, appending+-- separators.+--+-- >>> (emptySeparated :: Separated [Int] (String -> [String])) <.> emptySeparated+-- []+--+-- >>> [1,2] +: (\s -> [s, reverse s, drop 1 s]) +: emptySeparated <.> [3,4,5] +: "abc" +: emptySeparated+-- [[1,2,3,4,5],["abc","cba","bc"]]+instance Semigroup a => Apply (Separated a) where+ (<.>) =+ separatedAp (<>)++-- | Applies functions with element values, using a zipping operation, appending+-- separators. The identity operation is an infinite list of the emptySeparated separator+-- and the given element value.+--+-- >>> (emptySeparated :: Separated [Int] (String -> [String])) <*> emptySeparated+-- []+--+-- >>> [1,2] +: (\s -> [s, reverse s, drop 1 s]) +: emptySeparated <*> [3,4,5] +: "abc" +: emptySeparated+-- [[1,2,3,4,5],["abc","cba","bc"]]+instance Monoid a => Applicative (Separated a) where + (<*>) =+ separatedAp mappend+ pure =+ Separated . repeat . (,) mempty++-- |+--+-- >>> show (emptySeparated :: Separated () ())+-- "[]"+--+-- >>> show ('x' +: (6 :: Int) +: emptySeparated)+-- "['x',6]"+instance (Show a, Show b) => Show (Separated a b) where+ show (Separated x) =+ showSeparated id x++-- |+--+-- >>> ('x' +: (6 :: Int) +: emptySeparated) <> ('y' +: 7 +: emptySeparated)+-- ['x',6,'y',7]+instance Semigroup (Separated a b) where+ Separated x <> Separated y =+ Separated (x <> y) ++-- |+--+-- >>> ('x' +: (6 :: Int) +: emptySeparated) `mappend` ('y' +: 7 +: emptySeparated)+-- ['x',6,'y',7]+instance Monoid (Separated a b) where+ mappend =+ (<>)+ mempty =+ Separated mempty++----++instance Bifunctor Separated1 where+ bimap f g (Separated1 a x) =+ Separated1 (f a) (bimap g f x)++instance Bifoldable Separated1 where+ bifoldr f g z (Separated1 a x) = + f a (bifoldr g f z x)++instance Bitraversable Separated1 where+ bitraverse f g (Separated1 a x) =+ Separated1 <$> f a <*> bitraverse g f x++-- | Map across a @Separated1@ on the separator values.+--+-- >>> fmap (+1) (set tailL (1 +: 'b' +: 2 +: 'c' +: emptySeparated) (singleSeparated 'a' :: Separated1 Char Int))+-- ['a',2,'b',3,'c']+--+-- prop> fmap id (x :: Separated1 Int String) == x+--+-- prop> fmap (+1) (singleSeparated x :: Separated1 Char Int) == singleSeparated x+instance Functor (Separated1 b) where+ fmap =+ bimap id++-- | Applies functions with separator values, using a zipping operation,+-- appending elements.+--+-- >>> [1,2] +: reverse +: [3,4] +: emptySeparated <.> [5,6,7] +: "abc" +: [8] +: emptySeparated+-- [[1,2,5,6,7],"cba",[3,4,8]]+instance Semigroup b => Apply (Separated1 b) where+ (<.>) =+ separated1Ap (<>)++-- | Applies functions with separator values, using a zipping operation,+-- appending elements. The identity operation is an infinite list of the emptySeparated+-- element and the given separator value.+--+-- >>> [1,2] +: reverse +: [3,4] +: emptySeparated <*> [5,6,7] +: "abc" +: [8] +: emptySeparated+-- [[1,2,5,6,7],"cba",[3,4,8]]+instance Monoid b => Applicative (Separated1 b) where + (<*>) =+ separated1Ap mappend+ pure =+ Separated1 mempty . (swapped #) . pure++instance (Show b, Show a) => Show (Separated1 b a) where+ show (Separated1 a (Separated x)) =+ showSeparated (show a:) x++-- | The isomorphism that swaps elements with their separators.+--+-- >>> swapped # emptyPesarated+-- []+--+-- >>> swapped # ('x' -: 6 -: emptyPesarated)+-- [6,'x']+--+-- >>> emptyPesarated ^. swapped+-- []+--+-- >>> ('x' -: 6 -: emptyPesarated) ^. swapped+-- [6,'x']+instance Swapped Pesarated where+ swapped =+ _Wrapped . swapped . from _Wrapped++instance Bifunctor Pesarated where+ bimap f g (Pesarated x) =+ Pesarated (bimap g f x)++instance Bifoldable Pesarated where+ bifoldr f g z (Pesarated x) =+ bifoldr g f z x++instance Bitraversable Pesarated where+ bitraverse f g (Pesarated x) =+ Pesarated <$> bitraverse g f x++-- | Map across a @Pesarated@ on the element values.+--+-- prop> fmap id (x :: Pesarated Int String) == x+--+-- prop> \a b -> fmap (+1) (a -: b -: emptyPesarated) == (1+a) -: b -: emptyPesarated+instance Functor (Pesarated a) where+ fmap f (Pesarated x) =+ Pesarated (first f x)++-- | Applies functions with element values, using a zipping operation, appending+-- separators.+--+-- >>> (emptyPesarated :: Pesarated [Int] (String -> [String])) <.> emptyPesarated+-- []+--+-- >>> (\s -> [s, reverse s, drop 1 s]) -: [1,2] -: emptyPesarated <.> "abc" -: [3,4,5] -: emptyPesarated+-- [["abc","cba","bc"],[1,2,3,4,5]]+instance Semigroup a => Apply (Pesarated a) where+ Pesarated f <.> Pesarated a =+ Pesarated ((swapped # f <.> swapped # a) ^. swapped)++-- | Applies functions with element values, using a zipping operation, appending+-- separators. The identity operation is an infinite list of the emptySeparated separator+-- and the given element value.+--+-- >>> (emptySeparated :: Separated [Int] (String -> [String])) <*> emptySeparated+-- []+--+-- >>> (\s -> [s, reverse s, drop 1 s]) -: [1,2] -: emptyPesarated <*> "abc" -: [3,4,5] -: emptyPesarated+-- [["abc","cba","bc"],[1,2,3,4,5]]+instance Monoid a => Applicative (Pesarated a) where+ Pesarated f <*> Pesarated a =+ Pesarated ((swapped # f <*> swapped # a) ^. swapped)+ pure a =+ Pesarated (pure a ^. swapped)++-- |+--+-- >>> show (emptyPesarated :: Pesarated () ())+-- "[]"+--+-- >>> show ('x' -: (6 :: Int) -: emptyPesarated)+-- "['x',6]"+instance (Show a, Show b) => Show (Pesarated b a) where+ show (Pesarated x) =+ show x++-- |+--+-- >>> ('x' -: (6 :: Int) -: emptyPesarated) <> ('y' -: 7 -: emptyPesarated)+-- ['x',6,'y',7]+instance Semigroup (Pesarated b a) where+ Pesarated a <> Pesarated b =+ Pesarated (a <> b)++-- |+--+-- >>> ('x' -: (6 :: Int) -: emptyPesarated) `mappend` ('y' -: 7 -: emptyPesarated)+-- ['x',6,'y',7]+instance Monoid (Pesarated b a) where+ Pesarated a `mappend` Pesarated b =+ Pesarated (a <> b)+ mempty =+ Pesarated mempty++instance Bifunctor Pesarated1 where+ bimap f g (Pesarated1 x) =+ Pesarated1 (bimap g f x)++instance Bifoldable Pesarated1 where+ bifoldr f g z (Pesarated1 x) =+ bifoldr g f z x++instance Bitraversable Pesarated1 where+ bitraverse f g (Pesarated1 x) =+ Pesarated1 <$> bitraverse g f x++-- | Map across a @Pesarated1@ on the separator values.+--+-- >>> fmap toUpper (set tailL (1 -: 'b' -: 2 -: 'c' -: empty) (singlePesarated 'z' :: Pesarated1 Int Char) :: Pesarated1 Int Char)+-- ['Z',1,'B',2,'C']+--+-- prop> fmap id (x :: Pesarated1 Int String) == x+--+-- prop> fmap (+1) (singlePesarated x :: Pesarated1 Char Int) == singlePesarated (x + 1)+instance Functor (Pesarated1 a) where+ fmap f (Pesarated1 x) =+ Pesarated1 (first f x)++-- | Applies functions with separator values, using a zipping operation,+-- appending elements.+--+-- >>> id -: [1,2] -: reverse -: [3,4] -: emptyPesarated <.> "def" -: [5,6,7] -: "abc" -: [8] -: emptyPesarated+-- ["def",[1,2,5,6,7],"cba",[3,4,8]]+instance Semigroup a => Apply (Pesarated1 a) where+ f <.> a =+ pesarated1Ap (<>) f a++-- | Applies functions with separator values, using a zipping operation,+-- appending elements. The identity operation is an infinite list of the emptySeparated+-- element and the given separator value.+--+-- >>> id -: [1,2] -: reverse -: [3,4] -: emptyPesarated <*> "def" -: [5,6,7] -: "abc" -: [8] -: emptyPesarated+-- ["def",[1,2,5,6,7],"cba",[3,4,8]]+instance Monoid a => Applicative (Pesarated1 a) where+ f <*> a =+ pesarated1Ap mappend f a+ pure a =+ Pesarated1 (Separated1 a (pure a))++instance (Show a, Show b) => Show (Pesarated1 a b) where+ show (Pesarated1 x) =+ show x++---- not exported++showSeparated ::+ (Show a, Show s, Functor f) =>+ (f String -> [String])+ -> f (s, a)+ -> String+showSeparated f x =+ '[' : intercalate "," (f (fmap (\(s, a) -> show s <> "," <> show a) x)) <> "]"++separatedAp ::+ (s -> s -> s)+ -> Separated s (a -> b)+ -> Separated s a+ -> Separated s b+separatedAp opp (Separated f) (Separated a) =+ Separated (zipWith (\(s, f') (t, a') -> (s `opp` t, f' a')) f a) ++separated1Ap ::+ (a -> a -> a)+ -> Separated1 a (s -> t)+ -> Separated1 a s+ -> Separated1 a t+separated1Ap opp (Separated1 f (Separated fs)) (Separated1 a (Separated as)) =+ Separated1 (f `opp` a) (Separated (zipWith (\(s, f') (t, a') -> (s t, f' `opp` a')) fs as))++pesarated1Ap ::+ (a -> a -> a)+ -> Pesarated1 a (s -> t)+ -> Pesarated1 a s+ -> Pesarated1 a t+pesarated1Ap opp (Pesarated1 (Separated1 f (Separated fs))) (Pesarated1 (Separated1 a (Separated as))) =+ Pesarated1 (Separated1 (f a) (Separated (zipWith (\(s, f') (t, a') -> (s `opp` t, f' a')) fs as)))++-- | The isomorphism that shuffles the elements and separators one position.+--+-- >>> shift # ([], 6)+-- [6]+--+-- >>> shift # ([(5, 'x')], 6)+-- [5,'x',6]+--+-- >>> singleSeparated 6 ^. shift+-- ([],6)+--+-- >>> (5 +: 'x' +: singleSeparated 6) ^. shift+-- ([(5,'x')],6)+shift ::+ Iso (Separated1 a s) (Separated1 b t) ([(a, s)], a) ([(b, t)], b)+shift =+ let shiftR ([], a) =+ Separated1 a (Separated [])+ shiftR ((b, s):r, a) =+ let Separated1 z' (Separated w) = shiftR (r, b)+ in Separated1 z' (Separated ((s, a) : w))+ shiftL (Separated1 s' (Separated [])) =+ ([], s')+ shiftL (Separated1 s' (Separated ((a, t') : r))) =+ let (w, z) = shiftL (Separated1 t' (Separated r))+ in ((s', a) : w, z)+ in iso shiftL shiftR++makeWrapped ''Separated+makeWrapped ''Pesarated+makeWrapped ''Pesarated1
− src/Data/Separated/Separated.hs
@@ -1,443 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE FlexibleInstances #-}--module Data.Separated.Separated(- Separated-, separated-, Separated1-, separated1--- * Viewing-, separated1Head-, separated1Tail--- Constructing-, empty-, (+-)-, single--- * Appending-, shift-, (.++.)-, (++.)-, (.++)--- * Alternating-, separatedBy-, separatedBy1-) where--import Control.Applicative(Alternative(many))-import Data.Bifoldable(Bifoldable(bifoldr))-import Data.Bitraversable(Bitraversable(bitraverse))-import Data.Functor.Apply as Apply((<.>))-import Data.List(intercalate, zipWith, repeat)-import Data.Monoid as Monoid(mappend)-import Data.Semigroup as Semigroup((<>))-import Data.Separated.SeparatedCons(SeparatedCons((+:), SeparatedConsF, SeparatedConsG))-import Data.String(String)-import Papa hiding ((<.>))---- $setup--- >>> :set -XNoImplicitPrelude--- >>> import Data.Char(toUpper)--- >>> import Data.Either(isLeft)--- >>> import Text.Parsec(parse, char, digit)--- >>> 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)---newtype Separated a b =- Separated [(a, b)]- deriving (Eq, Ord)--makeWrapped ''Separated---- | The isomorphism that swaps elements with their separators.------ >>> swapped # empty--- []------ >>> swapped # ('x' +: 6 +: empty)--- [6,'x']------ >>> empty ^. swapped--- []------ >>> ('x' +: 6 +: empty) ^. swapped--- [6,'x']-instance Swapped Separated where- swapped =- let swap = (\(Separated x) -> Separated (fmap (\(a, b) -> (b, a)) x))- in iso swap swap--instance Bifunctor Separated where- bimap f g (Separated x) =- Separated (fmap (bimap f g) x)--instance Bifoldable Separated where- bifoldr f g z (Separated x) =- foldr (\(a, b) -> f a . g b) z x--instance Bitraversable Separated where- bitraverse f g (Separated x) =- Separated <$> traverse (\(a, b) -> (,) <$> f a <*> g b) x---- | Map across a @Separated@ on the element values.------ prop> fmap id (x :: Separated Int String) == x------ prop> \a b -> fmap (+1) (a +: b +: empty) == a +: (1+b) +: empty-instance Functor (Separated a) where- fmap =- bimap id---- | Applies functions with element values, using a zipping operation, appending--- separators.------ >>> (empty :: Separated [Int] (String -> [String])) <.> empty--- []------ >>> [1,2] +: (\s -> [s, reverse s, drop 1 s]) +: empty <.> [3,4,5] +: "abc" +: empty--- [[1,2,3,4,5],["abc","cba","bc"]]-instance Semigroup a => Apply (Separated a) where- (<.>) =- separatedAp (<>)---- | 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.------ >>> (empty :: Separated [Int] (String -> [String])) <*> empty--- []------ >>> [1,2] +: (\s -> [s, reverse s, drop 1 s]) +: empty <*> [3,4,5] +: "abc" +: empty--- [[1,2,3,4,5],["abc","cba","bc"]]-instance (Semigroup a, Monoid a) => Applicative (Separated a) where - (<*>) =- separatedAp (<>)- pure =- Separated . repeat . (,) mempty--instance (Show a, Show b) => Show (Separated a b) where- show (Separated x) =- showSeparated id x--instance Semigroup (Separated a b) where- Separated x <> Separated y =- Separated (x <> y) --instance Monoid (Separated a b) where- mappend =- (<>)- mempty =- Separated mempty--instance SeparatedCons Separated1 Separated where- type SeparatedConsF Separated = Separated1- type SeparatedConsG Separated1 = Separated- s +: Separated1 a (Separated x) =- Separated ((s, a) : x)--------data Separated1 b a =- Separated1 b (Separated a b)- deriving (Eq, Ord)--instance Bifunctor Separated1 where- bimap f g (Separated1 a x) =- Separated1 (f a) (bimap g f x)---- | Map across a @Separated1@ on the separator values.------ >>> fmap (+1) (set separated1Tail (1 +: 'b' +: 2 +: 'c' +: empty) (single 'a'))--- ['a',2,'b',3,'c']------ prop> fmap id (x :: Separated1 Int String) == x------ prop> fmap (+1) (single x) == single x-instance Functor (Separated1 b) where- fmap =- bimap id---- | Applies functions with separator values, using a zipping operation,--- appending elements.------ >>> [1,2] +: reverse +: [3,4] +: empty <.> [5,6,7] +: "abc" +: [8] +: empty--- [[1,2,5,6,7],"cba",[3,4,8]]-instance Semigroup b => Apply (Separated1 b) where- (<.>) =- separated1Ap (<>)--instance (Show b, Show a) => Show (Separated1 b a) where- show (Separated1 a (Separated x)) =- showSeparated (show a:) x- --- | 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.------ >>> [1,2] +: reverse +: [3,4] +: empty <*> [5,6,7] +: "abc" +: [8] +: empty--- [[1,2,5,6,7],"cba",[3,4,8]]-instance (Semigroup b, Monoid b) => Applicative (Separated1 b) where - (<*>) =- separated1Ap (<>)- pure =- Separated1 mempty . (swapped #) . pure--instance SeparatedCons Separated Separated1 where- type SeparatedConsF Separated1 = Separated- type SeparatedConsG Separated = Separated1- (+:) =- Separated1---------- | The isomorphism to a list of pairs of element and separator values.------ >>> separated # empty--- []------ >>> separated # ('x' +: 6 +: empty)--- [('x',6)]------ >>> [] ^. separated--- []------ >>> [(6, [])] ^. separated--- [6,[]]-separated ::- Iso [(a, b)] [(c, d)] (Separated a b) (Separated c d)-separated =- from _Wrapped--empty ::- Separated s a-empty =- Separated []---- | The isomorphism to element values interspersed with a separator.------ >>> separated1 # (single 6)--- (6,[])------ >>> separated1 # (5 +: 'x' +: single 6)--- (5,['x',6])------ >>> (6, empty) ^. separated1--- [6]------ >>> (5, 'x' +- 6) ^. separated1--- [5,'x',6]-separated1 ::- Iso (a, Separated s a) (b, Separated t b) (Separated1 a s) (Separated1 b t)-separated1 =- iso (uncurry Separated1) (\(Separated1 a x) -> (a, x))---- | A lens on the first element value.------ >>> single 7 ^. separated1Head--- 7------ prop> single x ^. separated1Head == (x :: Int)-separated1Head ::- Lens (Separated1 a t) (Separated1 a t) a a-separated1Head =- from separated1 . _1---- | A lens on the tail.------ prop> (d +: e +: single x) ^. separated1Tail == e +: x +: empty-separated1Tail ::- Lens (Separated1 a s) (Separated1 a t) (Separated s a) (Separated t a)-separated1Tail =- from separated1 . _2---- | One element and one separator.------ >>> 7 +- "abc"--- [7,"abc"]------ >>> 7 +: "abc" +: 8 +- "def"--- [7,"abc",8,"def"]-(+-) ::- s- -> a- -> Separated s a-s +- a =- s +: single a--infixl 9 +----- | Zero element values interspersed with one element.------ >>> single 4--- [4]------ prop> single x ^. separated1Tail == empty-single ::- a- -> Separated1 a s-single a =- Separated1 a empty---- | The isomorphism that shuffles the elements and separators one position.------ >>> shift # ([], 6)--- [6]------ >>> shift # ([(5, 'x')], 6)--- [5,'x',6]------ >>> single 6 ^. shift--- ([],6)------ >>> (5 +: 'x' +: single 6) ^. shift--- ([(5,'x')],6)-shift ::- Iso (Separated1 a s) (Separated1 b t) ([(a, s)], a) ([(b, t)], b)-shift =- let shiftR ([], a) =- Separated1 a (Separated [])- shiftR ((b, s):r, a) =- let Separated1 z' (Separated w) = shiftR (r, b)- in Separated1 z' (Separated ((s, a) : w))- shiftL (Separated1 s' (Separated [])) =- ([], s')- shiftL (Separated1 s' (Separated ((a, t') : r))) =- let (w, z) = shiftL (Separated1 t' (Separated r))- in ((s', a) : w, z)- in iso shiftL shiftR---- | Append two lists of separated values to produce a list of pairs of separator and element values.------ >>> single 7 .++. single 'a'--- [7,'a']------ 'a' +: single 7 .++. single 'b'--- ['a',7,'b']------ prop> a +: (b :: Separated Int Int) == a +: b -- (a +: (b .++. c)) == ((a +: b) .++ c)-(.++.) ::- Separated1 s a- -> Separated1 a s- -> Separated s a-Separated1 s x .++. Separated1 t (Separated y) =- let (q, r') = (s, x) ^. separated1 . shift- in Separated (q <> ((r', t) : y)) --infixr 5 .++.---- | Append element values interspersed with a separator to a list of pairs of separator and element values.------ >>> empty ++. single 7--- [7]------ >>> empty ++. 6 +: 'x' +: single 7--- [6,'x',7]------ >>> 'w' +: empty ++. 6 +: 'x' +: single 7--- ['w',6,'x',7]-(++.) ::- Separated s a- -> Separated1 s a- -> Separated1 s a-Separated x ++. Separated1 t y =- let (z, w') = separated1 . shift # (x, t)- in Separated1 z (w' <> y)--infixr 5 ++.---- | Append a list of pairs of separator and element values to element values interspersed with a separator.------ >>> single 7 .++ empty--- [7]------ >>> single 6 .++ 'x' +: 7 +: empty--- [6,'x',7]------ >>> 'w' +: single 6 .++ 'x' +: 7 +: empty--- ['w',6,'x',7]-(.++) ::- Separated1 a s- -> Separated s a- -> Separated1 a s-Separated1 a x .++ y =- Separated1 a (x <> y)--infixr 5 .++---- |------ >>> parse (separatedBy (char ',') digit) "test" ""--- Right []------ >>> isLeft (parse (separatedBy (char ',') digit) "test" ",")--- True------ >>> parse (separatedBy (char ',') digit) "test" ",1"--- Right [',','1']------ >>> isLeft (parse (separatedBy (char ',') digit) "test" ",1,")--- True------ >>> parse (separatedBy (char ',') digit) "test" ",1,2,3,4,5"--- Right [',','1',',','2',',','3',',','4',',','5']-separatedBy ::- Alternative f =>- f a- -> f b- -> f (Separated a b)-separatedBy a b =- Separated <$>- many- ((,) <$> a <*> b)---- |------ >>> isLeft (parse (separatedBy1 (char ',') digit) "test" "")--- True------ >>> parse (separatedBy1 (char ',') digit) "test" ","--- Right [',']------ >>> isLeft (parse (separatedBy1 (char ',') digit) "test" ",1")--- True------ >>> parse (separatedBy1 (char ',') digit) "test" ",1,"--- Right [',','1',',']------ >>> parse (separatedBy1 (char ',') digit) "test" ",1,2,3,4,5,"--- Right [',','1',',','2',',','3',',','4',',','5',',']-separatedBy1 ::- Alternative f =>- f b- -> f a- -> f (Separated1 b a)-separatedBy1 b a =- Separated1 <$> b <*> separatedBy a b--showSeparated ::- (Show a, Show s, Functor f) =>- (f String -> [String])- -> f (s, a)- -> String-showSeparated f x =- '[' : intercalate "," (f (fmap (\(s, a) -> show s <> "," <> show a) x)) <> "]"--separatedAp ::- (s -> s -> s)- -> Separated s (a -> b)- -> Separated s a- -> Separated s b-separatedAp opp (Separated f) (Separated a) =- Separated (zipWith (\(s, f') (t, a') -> (s `opp` t, f' a')) f a) --separated1Ap ::- (a -> a -> a)- -> Separated1 a (s -> t)- -> Separated1 a s- -> Separated1 a t-separated1Ap opp (Separated1 f (Separated fs)) (Separated1 a (Separated as)) =- Separated1 (f `opp` a) (Separated (zipWith (\(s, f') (t, a') -> (s t, f' `opp` a')) fs as))
− src/Data/Separated/SeparatedCons.hs
@@ -1,18 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE MultiParamTypeClasses #-}--module Data.Separated.SeparatedCons(- SeparatedCons(..)-) where---- | Prepend a value to a separated-like structure.-class (f ~ SeparatedConsF g, g ~ SeparatedConsG f) => SeparatedCons f g where- type SeparatedConsF g :: * -> * -> *- type SeparatedConsG f :: * -> * -> *- (+:) ::- a- -> f b a- -> g a b- -infixr 5 +: