{-# LANGUAGE MultiParamTypeClasses, ScopedTypeVariables, TypeOperators,
FunctionalDependencies, FlexibleContexts, UndecidableInstances,
FlexibleInstances #-}-- | Integers modulo n parametrised by the n. This also has type-level primality-- testing used for instantiating integral domain and field type classes. The -- primality testing is very slow, but it seem to be working fine for relatively-- small numbers.moduleAlgebra.Zn(Zn(..))whereimportData.TypeLevelhiding((+),(-),(*),mod,Eq,(==))importControl.Monad(liftM)importTest.QuickCheckimportAlgebra.Structures.FieldimportAlgebra.Z-- | The phantom type n represents which modulo to work in.newtypeZnn=ZnIntegerderiving(Eq,Ord)instanceShow(Znn)whereshow(Znn)=showninstanceNatn=>Num(Znn)whereZnx+Zny=Zn$(x+y)`mod`toNum(undefined::n)Znx*Zny=Zn$(x*y)`mod`toNum(undefined::n)abs(Znx)=Zn$absxsignum(Znx)=Zn$signumxnegate(Znx)=Zn$negatex`mod`toNum(undefined::n)fromIntegerx=Zn$fromInteger$x`mod`toNum(undefined::n)instanceNatn=>Arbitrary(Znn)wherearbitrary=liftMZn(choose(0,toNum(undefined::n)-1))instanceNatn=>Ring(Znn)where(<+>)=(+)zero=Zn0one=Zn1neg=negate(<*>)=(*)instanceNatn=>CommutativeRing(Znn)whereinstance(PrimenTrue,Natn)=>IntegralDomain(Znn)whereinstance(PrimenTrue,Natn)=>Field(Znn)whereinv(Znx)|x==1=Zn1|p`mod`x==0=error"Can't find the inverse of zero!"|otherwise=Zn$x<^>(p-2)`mod`pwherep=toNum(undefined::n)-- Z6 is not an integral domain and the typechecker will spot it!-- intDomZ6 = quickCheck (propIntegralDomain :: Z6 -> Z6 -> Z6 -> Property)-- Tests:typeZ3=ZnD3test1::Z3test1=inv2typeZ17=ZnD17test2::Z17test2=inv13-- Test that all elements of Z17 get correct inversestest3::Prelude.Booltest3=all(==1)[invx*x|x<-xs]wherexs::[Z17]=mapfromInteger[1..16]------------------------------------------------------------------------- Lots of crazy type-level stuff:class(Natx,Natsqrt)=>Sqrtxsqrt|x->sqrtinstance(Natx,Natsqrt,Sqrt'xD1GTsqrt)=>SqrtxsqrtclassSqrt'xyrsqrt|xyr->sqrtinstanceSubyD2y'=>Sqrt'xyLTy'instancePredyy'=>Sqrt'xyEQy'instance(ExpBaseyD2square,Succyy',Trichxsquarer,Sqrt'xy'rsqrt)=>Sqrt'xyGTsqrtsqrt::Sqrtxsqrt=>x->sqrtsqrt=undefinedclass(Natx,Data.TypeLevel.Boolb)=>Primexb|x->binstance(Sqrtxy,TrichyD1r,Prime'xyrb)=>PrimexbclassData.TypeLevel.Boolb=>Prime'xyrb|xyr->binstancePrime'xD1EQTrueinstance(Predyz,TrichzD1r1,Modxyrest,IsZerorestb1,Notb1b',Prime'xzr1b2,Andb'b2b3)=>Prime'xyGTb3prime::Primexb=>x->bprime=undefinedclassIsZeroxr|x->rinstanceIsZeroD0TrueinstanceIsZeroD1FalseinstanceIsZeroD2FalseinstanceIsZeroD3FalseinstanceIsZeroD4FalseinstanceIsZeroD5FalseinstanceIsZeroD6FalseinstanceIsZeroD7FalseinstanceIsZeroD8FalseinstanceIsZeroD9FalseinstancePosx=>IsZero(x:*d)False