{-# LANGUAGE TypeSynonymInstances #-}moduleSmartGroup(Splittable,groupAll,groupNum,groupLog)whereimportData.HeapasHeapimportData.SetasSetimportData.MapasMapimportData.MonoidimportData.CharimportqualifiedData.ByteString.Char8asSimportqualifiedData.ByteString.Lazy.Char8asLimportData.OrdclassOrda=>SplittableawherewordsOf::a->[a]instanceSplittableStringwherewordsOf=Prelude.filter((>3).length).wordsinstanceSplittableL.ByteStringwherewordsOf=Prelude.filter((>3).L.length).L.splitWithisSpaceinstanceSplittableS.ByteStringwherewordsOf=Prelude.filter((>3).S.length).S.splitWithisSpacedataStringLa=StringL{str::a,count::Int}deriving(Eq,Show)instanceOrda=>Ord(StringLa)wherecompare(StringLia)(StringLxb)=compareab`mappend`compareixdataSizeMapsa=Unsplittable(Seta)|Splittable(Map(StringLs)(Seta))deriving(Eq,Show)instance(Ords,Orda)=>Ord(SizeMapsa)wherecompare(Splittablea)(Splittableb)=compare(Map.sizea)(Map.sizeb)compare(Unsplittablea)(Unsplittableb)=compareabcompare(Unsplittable_)(Splittable_)=LTcompare(Splittable_)(Unsplittable_)=GTtypeWordAssocsa=MaxHeap(SizeMapsa)toSet(Unsplittablex)=xtoSet(Splittablex)=Set.unions(Map.elemsx)intLog::Int->IntintLog=truncate.logBase2.fromIntegralgroupWith::(Orda,Splittables)=>(Int->WordAssocsa->WordAssocsa)->Int->(a->s)->[a]->[[a]]groupWithfic=mkList.fi.mkAssoc.mkMapc-- | Divide list into as many groups as possiblegroupAll::(Orda,Splittables)=>Int->(a->s)->[a]->[[a]]groupAll=groupWith$\ix->letcycleSplitn=casesplitItinof(Justa)->cycleSplitaNothing->nincycleSplitx-- | Divide list into about n different groupsgroupNum::(Orda,Splittables)=>Int->Int->(a->s)->[a]->[[a]]groupNumi=groupWith$\x->letsplitTimesnm=ifHeap.sizem>=nthenmelsecasesplitItxmof(Justa)->splitTimesnaNothing->minsplitTimesi-- | Divide list into groups such that the amount of groups-- equals the log of the number of elementsgroupLog::(Orda,Splittables)=>Int->(a->s)->[a]->[[a]]groupLogifs=groupNum(intLog(lengths))ifsmkMap::(Orda,Splittables)=>(a->s)->[a]->Maps(Seta)mkMapf=foldl(\mx->foldl(\m'i->Map.alter(Just.maybe(Set.singletonx)(Set.insertx))im')m(wordsOf$fx))Map.emptymkAssoc::(Orda,Splittables)=>Maps(Seta)->MaxHeap(SizeMapsa)mkAssocm=Heap.singleton.Splittable.Map.mapKeys(\k->StringLk(Set.size(mMap.!k)))$msplitIt::(Orda,Splittables)=>Int->WordAssocsa->Maybe(WordAssocsa)splitItis=caseHeap.viewsofNothing->Nothing(Just((Unsplittable_),_))->Nothing(Just((Splittablex),xs))->do(as,b)<-Map.maxViewxx1<-sizeMapi$flipMap.mapMaybeb$\n->letm=Set.differencenasinifSet.nullmthenNothingelseJustmx2<-sizeMapi$flipMap.mapMaybeb$\n->letm=Set.intersectionnasinifSet.nullmthenNothingelseJustmletx3=asSet.\\(Set.unions(Map.elemsb))return$(ifSet.nullx3thenidelseHeap.insert(Unsplittablex3))$Heap.insertx1$Heap.insertx2xssizeMap::(Orda,Splittables)=>Int->(Map(StringLs)(Seta))->Maybe(SizeMapsa)sizeMapim=ifMap.nullmthenNothingelseJust$caseMap.findMaxmof(StringL_c,_)->ifc>=ithenSplittablemelseUnsplittable(Set.unions(Map.elemsm))-- findMax fails on empty maps-- maxView might not return a Just value-- known offenders-- ["","","",""] (empty strings have no words to key off of)mkList::(Orda,Splittables)=>WordAssocsa->[[a]]mkList=Prelude.map(Set.toList.toSet).Heap.toList