-- Copyright (c) 2011, David Amos. All rights reserved.{-# LANGUAGE NoMonomorphismRestriction, TupleSections #-}-- |A module of simple utility functions which are used throughout the rest of the librarymoduleMath.Core.UtilswhereimportData.ListasLimportqualifiedData.SetasStoSet=S.toList.S.fromList-- Merge two ordered listsets. Elements appearing in both inputs appear only once in the outputmergeSet(x:xs)(y:ys)=casecomparexyofLT->x:mergeSetxs(y:ys)EQ->x:mergeSetxsysGT->y:mergeSet(x:xs)ysmergeSetxsys=xs++yspairs(x:xs)=map(x,)xs++pairsxspairs[]=[]ordpairxy|x<y=(x,y)|otherwise=(y,x)-- fold a comparison operator through a listfoldcmplp(x1:x2:xs)=px1x2&&foldcmplp(x2:xs)foldcmpl__=True-- This can be expressed as a pure fold:-- foldcmpl cmp (x:xs) = snd $ foldl (\(bool,x') x -> (bool && cmp x' x, x)) (True,x)-- foldcmpl _ [] = True-- However, that is less efficient, as we can't abort as soon as we fail-- (What about using the Maybe monad?)-- for use with L.sortBycmpfstxy=compare(fstx)(fsty)-- for use with L.groupByeqfstxy=(==)(fstx)(fsty)fromBasebxs=foldl'(\nx->n*b+x)0xs-- |Given a set @xs@, represented as an ordered list, @powersetdfs xs@ returns the list of all subsets of xs, in lex orderpowersetdfs::[a]->[[a]]powersetdfsxs=mapreverse$dfs[([],xs)]wheredfs((ls,rs):nodes)=ls:dfs(successors(ls,rs)++nodes)dfs[]=[]successors(ls,rs)=[(r:ls,rs')|r:rs'<-L.tailsrs]-- |Given a set @xs@, represented as an ordered list, @powersetbfs xs@ returns the list of all subsets of xs, in shortlex orderpowersetbfs::[a]->[[a]]powersetbfsxs=mapreverse$bfs[([],xs)]wherebfs((ls,rs):nodes)=ls:bfs(nodes++successors(ls,rs))bfs[]=[]successors(ls,rs)=[(r:ls,rs')|r:rs'<-L.tailsrs]-- |Given a positive integer @k@, and a set @xs@, represented as a list,-- @combinationsOf k xs@ returns all k-element subsets of xs.-- The result will be in lex order, relative to the order of the xs.combinationsOf::Int->[a]->[[a]]combinationsOf0_=[[]]combinationsOf_[]=[]combinationsOfk(x:xs)|k>0=map(x:)(combinationsOf(k-1)xs)++combinationsOfkxs-- |@choose n k@ is the number of ways of choosing k distinct elements from an n-setchoose::(Integrala)=>a->a->achoosenk=product[n-k+1..n]`div`product[1..k]-- |The class of finite setsclassFinSetxwhereelts::[x]-- |A class representing algebraic structures having an inverse operation.-- Although strictly speaking the Num precondition means that we are requiring the structure-- also to be a ring, we do sometimes bend the rules (eg permutation groups).-- Note also that we don't insist that every element has an inverse.classNuma=>HasInversesawhereinverse::a->ainfix8^--- |A trick: x^-1 returns the inverse of x(^-)::(HasInversesa,Integralb)=>a->b->ax^-n=inversex^n