{-
Copyright 2011 Mario Blazevic
This file is part of the Streaming Component Combinators (SCC) project.
The SCC project is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
version.
SCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with SCC. If not, see
<http://www.gnu.org/licenses/>.
-}-- | This module defines the 'FactorialMonoid' class.-- moduleData.Monoid.Factorial(-- * ClassesFactorialMonoid(..),-- * Functionsmbreak,mlength,mmap,mreverse,mtakeWhile,mdropWhile)whereimportData.Monoid(Monoid(..))importqualifiedData.ListasListimportqualifiedData.ByteStringasByteStringimportqualifiedData.TextasTextimportData.ByteString(ByteString)importData.Text(Text)-- | Class of monoids that can be split into irreducible factors, /i.e./, atoms or primes. The methods of this class-- satisfy the following laws:-- -- > mconcat . factors == id-- > factors mempty == []-- > all (\f-> factors f == [f]) (factors m)-- > factors == unfoldr splitPrimePrefix == reverse . unfoldr (fmap swap . splitPrimeSuffix)-- > primePrefix == maybe mempty fst . splitPrimePrefix-- > primeSuffix == maybe mempty snd . splitPrimeSuffix-- > mfoldl f f0 == foldl f f0 . factors-- > mfoldr f f0 == foldr f f0 . factors-- > mspan p m == (mconcat l, mconcat r) where (l, r) = span p (factors m)-- -- A minimal instance definition must implement 'factors' or 'splitPrimePrefix'.classMonoidm=>FactorialMonoidmwhere-- | Returns a list of all prime factors; inverse of mconcat.factors::m->[m]-- | The prime prefix, 'mempty' if none.primePrefix::m->m-- | The prime suffix, 'mempty' if none.primeSuffix::m->m-- | Splits the argument into its prime prefix and the remaining suffix. Returns 'Nothing' for 'mempty'.splitPrimePrefix::m->Maybe(m,m)-- | Splits the argument into its prime suffix and the remaining prefix. Returns 'Nothing' for 'mempty'.splitPrimeSuffix::m->Maybe(m,m)-- | Like 'foldl' on the list of primes.mfoldl::(a->m->a)->a->m->a-- | Like 'foldr' on the list of primes.mfoldr::(m->a->a)->a->m->a-- | Like 'span' on the list of primes.mspan::(m->Bool)->m->(m,m)factors=List.unfoldrsplitPrimePrefixprimePrefix=maybememptyfst.splitPrimePrefixprimeSuffix=maybememptysnd.splitPrimeSuffixsplitPrimePrefixx=casefactorsxof[]->Nothingprefix:rest->Just(prefix,mconcatrest)splitPrimeSuffixx=casefactorsxof[]->Nothingfs->Just(mconcat(List.initfs),List.lastfs)mfoldlff0=List.foldlff0.factorsmfoldrff0=List.foldrff0.factorsmspanp=mfoldrf(mempty,mempty)wherefs(prefix,suffix)=ifpsthen(mappendsprefix,suffix)else(mempty,mappends(mappendprefixsuffix))instanceFactorialMonoid[x]wherefactorsxs=List.map(:[])xsprimePrefix[]=[]primePrefix(x:xs)=[x]primeSuffix[]=[]primeSuffixxs=[List.lastxs]splitPrimePrefix[]=NothingsplitPrimePrefix(x:xs)=Just([x],xs)splitPrimeSuffix[]=NothingsplitPrimeSuffixxs=Just(splitidxs)wheresplitflast@[x]=(f[],last)splitf(x:xs)=split(f.(x:))xsmfoldl_acc[]=accmfoldlfacc(x:xs)=mfoldlf(facc[x])xsmfoldr_f0[]=f0mfoldrff0(x:xs)=f[x](mfoldrff0xs)mspanf=List.span(f.(:[]))instanceFactorialMonoidByteStringwherefactorsx=factorize(ByteString.lengthx)xwherefactorize0xs=[]factorizenxs=x:factorize(predn)xs'where(x,xs')=ByteString.splitAt1xsprimePrefix=ByteString.take1primeSuffixx=ByteString.drop(ByteString.lengthx-1)xsplitPrimePrefixx=ifByteString.nullxthenNothingelseJust(ByteString.splitAt1x)splitPrimeSuffixx=ifByteString.nullxthenNothingelseJust(ByteString.splitAt(ByteString.lengthx-1)x)mfoldlf=ByteString.foldlf'wheref'abyte=fa(ByteString.singletonbyte)mfoldrf=ByteString.foldrf'wheref'bytea=f(ByteString.singletonbyte)amspanfx=ByteString.splitAt(findIndex0x)xwherefindIndexix|ByteString.nullx=ifindIndexix=iff(ByteString.take1x)thenfindIndex(succi)(ByteString.drop1x)elseiinstanceFactorialMonoidTextwherefactors=Text.chunksOf1primePrefix=Text.take1primeSuffixx=ifText.nullxthenText.emptyelseText.singleton(Text.lastx)splitPrimePrefixx=ifText.nullxthenNothingelseJust(Text.splitAt1x)splitPrimeSuffixx=ifText.nullxthenNothingelseJust(Text.splitAt(Text.lengthx-1)x)mfoldlf=Text.foldlf'wheref'achar=fa(Text.singletonchar)mfoldrf=Text.foldrf'wheref'chara=f(Text.singletonchar)amspanf=Text.span(f.Text.singleton)-- | A 'List.break' equivalent.mbreak::FactorialMonoidm=>(m->Bool)->m->(m,m)mbreak=mspan.(not.)-- | A 'List.length' equivalent.mlength::FactorialMonoidm=>m->Intmlength=List.length.factors-- | A 'List.map' equivalent.mmap::FactorialMonoidm=>(m->m)->m->mmmapf=mconcat.List.mapf.factors-- | A 'List.reverse' equivalent.mreverse::FactorialMonoidm=>m->mmreverse=mconcat.List.reverse.factors-- | A 'List.takeWhile' equivalent.mtakeWhile::FactorialMonoidm=>(m->Bool)->m->mmtakeWhilep=fst.mspanp-- | A 'List.dropWhile' equivalent.mdropWhile::FactorialMonoidm=>(m->Bool)->m->mmdropWhilep=snd.mspanp