{- |
Module : Language.Scheme.Numerical
Copyright : Justin Ethier
Licence : MIT (see LICENSE in the distribution)
Maintainer : github.com/justinethier
Stability : experimental
Portability : portable
This module implements the numerical tower.
-}moduleLanguage.Scheme.Numerical(-- * Generic functionsnumSub,numMul,numDiv,numAdd,numMod,numRationalize,numBoolBinopEq,numBoolBinopGt,numBoolBinopGte,numBoolBinopLt,numBoolBinopLte,numCast,numDenominator,numNumerator,numInexact2Exact,numExact2Inexact,num2String,unpackNum,numericBinop-- * Floating point functions,numFloor,numCeiling,numTruncate,numRound,numExpt,numSqrt,numExp,numLog-- * Trigonometric functions,numSin,numCos,numTan,numAsin,numAcos,numAtan-- * Complex functions,buildComplex,numMakePolar,numRealPart,numImagPart,numMagnitude,numAngle,numMakeRectangular-- * Predicates,isComplex,isReal,isRational,isInteger,isNumber,isFloatAnInteger)whereimportLanguage.Scheme.TypesimportControl.Monad.ErrorimportData.Charhiding(isNumber)importData.CompleximportData.FixedimportData.RatioimportNumericimportText.Printf-- |A helper function to perform a numeric operation on two valuesnumericBinop::(Integer->Integer->Integer)->[LispVal]->ThrowsErrorLispValnumericBinop_singleVal@[_]=throwError$NumArgs(Just2)singleValnumericBinopopaparams=mapMunpackNumaparams>>=return.Number.foldl1op-- - Begin GenUtil - http://repetae.net/computer/haskell/GenUtil.hsfoldlM::Monadm=>(a->b->ma)->a->[b]->mafoldlMfv(x:xs)=(fvx)>>=\a->foldlMfaxsfoldlM_v[]=returnvfoldl1M::Monadm=>(a->a->ma)->[a]->mafoldl1Mf(x:xs)=foldlMfxxsfoldl1M__=error"Unexpected error in foldl1M"-- end GenUtil{- FUTURE: as a general comment here, operations need to be more permissive of the
numerical types they accept. Within reason, a user should not have to know
what numerical type they are passing when using these functions -}-- |Add the given numbersnumAdd::[LispVal]->ThrowsErrorLispValnumAdd[]=return$Number0numAddaparams=dofoldl1M(\ab->doAdd=<<(numCast[a,b]))aparamswheredoAdd(List[(Numbera),(Numberb)])=return$Number$a+bdoAdd(List[(Floata),(Floatb)])=return$Float$a+bdoAdd(List[(Rationala),(Rationalb)])=return$Rational$a+bdoAdd(List[(Complexa),(Complexb)])=return$Complex$a+bdoAdd_=throwError$Default"Unexpected error in +"-- |Subtract the given numbersnumSub::[LispVal]->ThrowsErrorLispValnumSub[]=throwError$NumArgs(Just1)[]numSub[Numbern]=return$Number$-1*nnumSub[Floatn]=return$Float$-1*nnumSub[Rationaln]=return$Rational$-1*nnumSub[Complexn]=return$Complex$-1*nnumSubaparams=dofoldl1M(\ab->doSub=<<(numCast[a,b]))aparamswheredoSub(List[(Numbera),(Numberb)])=return$Number$a-bdoSub(List[(Floata),(Floatb)])=return$Float$a-bdoSub(List[(Rationala),(Rationalb)])=return$Rational$a-bdoSub(List[(Complexa),(Complexb)])=return$Complex$a-bdoSub_=throwError$Default"Unexpected error in -"-- |Multiply the given numbersnumMul::[LispVal]->ThrowsErrorLispValnumMul[]=return$Number1numMulaparams=dofoldl1M(\ab->doMul=<<(numCast[a,b]))aparamswheredoMul(List[(Numbera),(Numberb)])=return$Number$a*bdoMul(List[(Floata),(Floatb)])=return$Float$a*bdoMul(List[(Rationala),(Rationalb)])=return$Rational$a*bdoMul(List[(Complexa),(Complexb)])=return$Complex$a*bdoMul_=throwError$Default"Unexpected error in *"-- |Divide the given numbersnumDiv::[LispVal]->ThrowsErrorLispValnumDiv[]=throwError$NumArgs(Just1)[]numDiv[Number0]=throwError$DivideByZeronumDiv[Rational0]=throwError$DivideByZeronumDiv[Numbern]=return$Rational$1/(fromIntegern)numDiv[Floatn]=return$Float$1.0/nnumDiv[Rationaln]=return$Rational$1/nnumDiv[Complexn]=return$Complex$1/nnumDivaparams=dofoldl1M(\ab->doDiv=<<(numCast[a,b]))aparamswheredoDiv(List[(Numbera),(Numberb)])=ifb==0thenthrowError$DivideByZeroelseif(modab)==0thenreturn$Number$divab-- Convert to a rational if the result is not an integerelsereturn$Rational$(fromIntegera)/(fromIntegerb)doDiv(List[(Floata),(Floatb)])=ifb==0.0thenthrowError$DivideByZeroelsereturn$Float$a/bdoDiv(List[(Rationala),(Rationalb)])=ifb==0thenthrowError$DivideByZeroelsereturn$Rational$a/bdoDiv(List[(Complexa),(Complexb)])=ifb==0thenthrowError$DivideByZeroelsereturn$Complex$a/bdoDiv_=throwError$Default"Unexpected error in /"-- |Take the modulus of the given numbersnumMod::[LispVal]->ThrowsErrorLispValnumMod[]=return$Number1numModaparams=dofoldl1M(\ab->doMod=<<(numCast[a,b]))aparamswheredoMod(List[(Numbera),(Numberb)])=return$Number$mod'abdoMod(List[(Floata),(Floatb)])=return$Float$mod'abdoMod(List[(Rationala),(Rationalb)])=return$Rational$mod'abdoMod(List[(Complex_),(Complex_)])=throwError$Default"modulo not implemented for complex numbers"doMod_=throwError$Default"Unexpected error in modulo"-- |Compare a series of numbers using a given numeric comparison-- function and an array of lisp valuesnumBoolBinopComparecmpn1(n2:ns)=doList[n1',n2']<-numCast[n1,n2]result<-cmpn1'n2'caseresultofBoolTrue->numBoolBinopComparecmpn2'ns_->return$BoolFalsenumBoolBinopCompare___=return$BoolTrue-- |Numeric equalsnumBoolBinopEq::[LispVal]->ThrowsErrorLispValnumBoolBinopEq[]=throwError$NumArgs(Just0)[]numBoolBinopEq(n:ns)=numBoolBinopComparecmpnnswherefab=a==bcmp(Numbera)(Numberb)=return$Bool$fabcmp(Floata)(Floatb)=return$Bool$fabcmp(Rationala)(Rationalb)=return$Bool$fabcmp(Complexa)(Complexb)=return$Bool$fabcmp__=throwError$Default"Unexpected error in ="-- |Numeric greater thannumBoolBinopGt::[LispVal]->ThrowsErrorLispValnumBoolBinopGt[]=throwError$NumArgs(Just0)[]numBoolBinopGt(n:ns)=numBoolBinopComparecmpnnswherefab=a>bcmp(Numbera)(Numberb)=return$Bool$fabcmp(Floata)(Floatb)=return$Bool$fabcmp(Rationala)(Rationalb)=return$Bool$fabcmp__=throwError$Default"Unexpected error in >"-- |Numeric greater than equalnumBoolBinopGte::[LispVal]->ThrowsErrorLispValnumBoolBinopGte[]=throwError$NumArgs(Just0)[]numBoolBinopGte(n:ns)=numBoolBinopComparecmpnnswherefab=a>=bcmp(Numbera)(Numberb)=return$Bool$fabcmp(Floata)(Floatb)=return$Bool$fabcmp(Rationala)(Rationalb)=return$Bool$fabcmp__=throwError$Default"Unexpected error in >="-- |Numeric less than numBoolBinopLt::[LispVal]->ThrowsErrorLispValnumBoolBinopLt[]=throwError$NumArgs(Just0)[]numBoolBinopLt(n:ns)=numBoolBinopComparecmpnnswherefab=a<bcmp(Numbera)(Numberb)=return$Bool$fabcmp(Floata)(Floatb)=return$Bool$fabcmp(Rationala)(Rationalb)=return$Bool$fabcmp__=throwError$Default"Unexpected error in <"-- |Numeric less than equalnumBoolBinopLte::[LispVal]->ThrowsErrorLispValnumBoolBinopLte[]=throwError$NumArgs(Just0)[]numBoolBinopLte(n:ns)=numBoolBinopComparecmpnnswherefab=a<=bcmp(Numbera)(Numberb)=return$Bool$fabcmp(Floata)(Floatb)=return$Bool$fabcmp(Rationala)(Rationalb)=return$Bool$fabcmp__=throwError$Default"Unexpected error in <="-- |Accept two numbers and cast one of them to the appropriate type, if necessarynumCast::[LispVal]->ThrowsErrorLispValnumCast[a@(Number_),b@(Number_)]=return$List[a,b]numCast[a@(Float_),b@(Float_)]=return$List[a,b]numCast[a@(Rational_),b@(Rational_)]=return$List[a,b]numCast[a@(Complex_),b@(Complex_)]=return$List[a,b]numCast[(Numbera),b@(Float_)]=return$List[Float$fromIntegera,b]numCast[(Numbera),b@(Rational_)]=return$List[Rational$fromIntegera,b]numCast[(Numbera),b@(Complex_)]=return$List[Complex$fromIntegera,b]numCast[a@(Float_),(Numberb)]=return$List[a,Float$fromIntegerb]numCast[a@(Float_),(Rationalb)]=return$List[a,Float$fromRationalb]numCast[(Floata),b@(Complex_)]=return$List[Complex$a:+0,b]numCast[a@(Rational_),(Numberb)]=return$List[a,Rational$fromIntegerb]numCast[(Rationala),b@(Float_)]=return$List[Float$fromRationala,b]numCast[(Rationala),b@(Complex_)]=return$List[Complex$(fromInteger$numeratora)/(fromInteger$denominatora),b]numCast[a@(Complex_),(Numberb)]=return$List[a,Complex$fromIntegerb]numCast[a@(Complex_),(Floatb)]=return$List[a,Complex$b:+0]numCast[a@(Complex_),(Rationalb)]=return$List[a,Complex$(fromInteger$numeratorb)/(fromInteger$denominatorb)]numCast[a,b]=caseaofNumber_->doThrowErrorbFloat_->doThrowErrorbRational_->doThrowErrorbComplex_->doThrowErrorb_->doThrowErrorawheredoThrowErrornum=throwError$TypeMismatch"number"numnumCast_=throwError$Default"Unexpected error in numCast"-- |Convert the given number to a rationalnumRationalize::[LispVal]->ThrowsErrorLispValnumRationalize[(Numbern)]=return$Rational$toRationalnnumRationalize[(Floatn)]=return$Rational$toRationalnnumRationalize[n@(Rational_)]=returnnnumRationalize[x]=throwError$TypeMismatch"number"xnumRationalizebadArgList=throwError$NumArgs(Just1)badArgList-- |Round the given numbernumRound::[LispVal]->ThrowsErrorLispValnumRound[n@(Number_)]=returnnnumRound[(Rationaln)]=return$Number$roundnnumRound[(Floatn)]=return$Float$fromInteger$roundnnumRound[(Complexn)]=doreturn$Complex$(fromInteger$round$realPartn):+(fromInteger$round$imagPartn)numRound[x]=throwError$TypeMismatch"number"xnumRoundbadArgList=throwError$NumArgs(Just1)badArgList-- |Floor the given numbernumFloor::[LispVal]->ThrowsErrorLispValnumFloor[n@(Number_)]=returnnnumFloor[(Rationaln)]=return$Number$floornnumFloor[(Floatn)]=return$Float$fromInteger$floornnumFloor[(Complexn)]=doreturn$Complex$(fromInteger$floor$realPartn):+(fromInteger$floor$imagPartn)numFloor[x]=throwError$TypeMismatch"number"xnumFloorbadArgList=throwError$NumArgs(Just1)badArgList-- |Take the ceiling of the given numbernumCeiling::[LispVal]->ThrowsErrorLispValnumCeiling[n@(Number_)]=returnnnumCeiling[(Rationaln)]=return$Number$ceilingnnumCeiling[(Floatn)]=return$Float$fromInteger$ceilingnnumCeiling[(Complexn)]=doreturn$Complex$(fromInteger$ceiling$realPartn):+(fromInteger$ceiling$imagPartn)numCeiling[x]=throwError$TypeMismatch"number"xnumCeilingbadArgList=throwError$NumArgs(Just1)badArgList-- |Truncate the given numbernumTruncate::[LispVal]->ThrowsErrorLispValnumTruncate[n@(Number_)]=returnnnumTruncate[(Rationaln)]=return$Number$truncatennumTruncate[(Floatn)]=return$Float$fromInteger$truncatennumTruncate[(Complexn)]=doreturn$Complex$(fromInteger$truncate$realPartn):+(fromInteger$truncate$imagPartn)numTruncate[x]=throwError$TypeMismatch"number"xnumTruncatebadArgList=throwError$NumArgs(Just1)badArgList-- |SinenumSin::[LispVal]->ThrowsErrorLispValnumSin[(Numbern)]=return$Float$sin$fromIntegernnumSin[(Floatn)]=return$Float$sinnnumSin[(Rationaln)]=return$Float$sin$fromRationalnnumSin[(Complexn)]=return$Complex$sinnnumSin[x]=throwError$TypeMismatch"number"xnumSinbadArgList=throwError$NumArgs(Just1)badArgList-- |CosinenumCos::[LispVal]->ThrowsErrorLispValnumCos[(Numbern)]=return$Float$cos$fromIntegernnumCos[(Floatn)]=return$Float$cosnnumCos[(Rationaln)]=return$Float$cos$fromRationalnnumCos[(Complexn)]=return$Complex$cosnnumCos[x]=throwError$TypeMismatch"number"xnumCosbadArgList=throwError$NumArgs(Just1)badArgList-- |TangentnumTan::[LispVal]->ThrowsErrorLispValnumTan[(Numbern)]=return$Float$tan$fromIntegernnumTan[(Floatn)]=return$Float$tannnumTan[(Rationaln)]=return$Float$tan$fromRationalnnumTan[(Complexn)]=return$Complex$tannnumTan[x]=throwError$TypeMismatch"number"xnumTanbadArgList=throwError$NumArgs(Just1)badArgList-- |ArcsinenumAsin::[LispVal]->ThrowsErrorLispValnumAsin[(Numbern)]=return$Float$asin$fromIntegernnumAsin[(Floatn)]=return$Float$asinnnumAsin[(Rationaln)]=return$Float$asin$fromRationalnnumAsin[(Complexn)]=return$Complex$asinnnumAsin[x]=throwError$TypeMismatch"number"xnumAsinbadArgList=throwError$NumArgs(Just1)badArgList-- |ArccosinenumAcos::[LispVal]->ThrowsErrorLispValnumAcos[(Numbern)]=return$Float$acos$fromIntegernnumAcos[(Floatn)]=return$Float$acosnnumAcos[(Rationaln)]=return$Float$acos$fromRationalnnumAcos[(Complexn)]=return$Complex$acosnnumAcos[x]=throwError$TypeMismatch"number"xnumAcosbadArgList=throwError$NumArgs(Just1)badArgList-- |ArctangentnumAtan::[LispVal]->ThrowsErrorLispValnumAtan[(Numbern)]=return$Float$atan$fromIntegernnumAtan[Numbery,Numberx]=return$Float$phase$(fromIntegerx):+(fromIntegery)numAtan[(Floatn)]=return$Float$atannnumAtan[Floaty,Floatx]=return$Float$phase$x:+ynumAtan[(Rationaln)]=return$Float$atan$fromRationalnnumAtan[Rationaly,Rationalx]=return$Float$phase$(fromRationalx):+(fromRationaly)numAtan[(Complexn)]=return$Complex$atannnumAtan[x]=throwError$TypeMismatch"number"xnumAtanbadArgList=throwError$NumArgs(Just1)badArgList-- |Take the square root of the given numbernumSqrt::[LispVal]->ThrowsErrorLispValnumSqrt[(Numbern)]=ifn>=0thenreturn$Float$sqrt$fromIntegernelsereturn$Complex$sqrt((fromIntegern):+0)numSqrt[(Floatn)]=ifn>=0thenreturn$Float$sqrtnelsereturn$Complex$sqrt(n:+0)numSqrt[(Rationaln)]=numSqrt[Float$fromRationaln]numSqrt[(Complexn)]=return$Complex$sqrtnnumSqrt[x]=throwError$TypeMismatch"number"xnumSqrtbadArgList=throwError$NumArgs(Just1)badArgList-- |Raise the first number to the power of the secondnumExpt::[LispVal]->ThrowsErrorLispValnumExpt[(Numbern),(Numberp)]=return$Float$(fromIntegern)^pnumExpt[(Rationaln),(Numberp)]=return$Float$(fromRationaln)^pnumExpt[(Floatn),(Numberp)]=return$Float$n^pnumExpt[(Complexn),(Numberp)]=return$Complex$n^pnumExpt[_,y]=throwError$TypeMismatch"integer"ynumExptbadArgList=throwError$NumArgs(Just2)badArgList{- numExpt params = do
foldl1M (\a b -> doExpt =<< (numCast [a, b])) params
where doExpt (List [(Number a), (Number b)]) = return $ Float $ (fromInteger a) ^ (fromInteger b)
-- doExpt (List [(Rational a), (Rational b)]) = return $ Float $ fromRational $ a ^ b
doExpt (List [(Float a), (Float b)]) = return $ Float $ a ^ b
-- doExpt (List [(Complex a), (Complex b)]) = return $ Complex $ a ^ b -}-- |Take the exponent of the given numbernumExp::[LispVal]->ThrowsErrorLispValnumExp[(Numbern)]=return$Float$exp$fromIntegernnumExp[(Floatn)]=return$Float$expnnumExp[(Rationaln)]=return$Float$exp$fromRationalnnumExp[(Complexn)]=return$Complex$expnnumExp[x]=throwError$TypeMismatch"number"xnumExpbadArgList=throwError$NumArgs(Just1)badArgList-- |Compute the log of a given numbernumLog::[LispVal]->ThrowsErrorLispValnumLog[(Numbern)]=return$Float$log$fromIntegernnumLog[(Floatn)]=return$Float$lognnumLog[(Rationaln)]=return$Float$log$fromRationalnnumLog[(Complexn)]=return$Complex$lognnumLog[x]=throwError$TypeMismatch"number"xnumLogbadArgList=throwError$NumArgs(Just1)badArgList-- Complex number functions-- |Create a complex numberbuildComplex::LispVal-- ^ Real part->LispVal-- ^ Imaginary part->ThrowsErrorLispVal-- ^ Complex numberbuildComplex(Numberx)(Numbery)=return$Complex$(fromIntegerx):+(fromIntegery)buildComplex(Numberx)(Rationaly)=return$Complex$(fromIntegerx):+(fromRationaly)buildComplex(Numberx)(Floaty)=return$Complex$(fromIntegerx):+ybuildComplex(Rationalx)(Numbery)=return$Complex$(fromRationalx):+(fromIntegery)buildComplex(Rationalx)(Rationaly)=return$Complex$(fromRationalx):+(fromRationaly)buildComplex(Rationalx)(Floaty)=return$Complex$(fromRationalx):+ybuildComplex(Floatx)(Numbery)=return$Complex$x:+(fromIntegery)buildComplex(Floatx)(Rationaly)=return$Complex$x:+(fromRationaly)buildComplex(Floatx)(Floaty)=return$Complex$x:+ybuildComplexxy=throwError$TypeMismatch"number"$List[x,y]-- |Create a complex number given its real and imaginary partsnumMakeRectangular::[LispVal]->ThrowsErrorLispValnumMakeRectangular[x,y]=buildComplexxynumMakeRectangularbadArgList=throwError$NumArgs(Just2)badArgList-- |Create a complex number from its magnitude and phase (angle)numMakePolar::[LispVal]->ThrowsErrorLispValnumMakePolar[(Floatx),(Floaty)]=return$Complex$mkPolarxynumMakePolar[(Float_),y]=throwError$TypeMismatch"real"ynumMakePolar[x,(Float_)]=throwError$TypeMismatch"real real"$xnumMakePolarbadArgList=throwError$NumArgs(Just2)badArgList-- |The phase of a complex numbernumAngle::[LispVal]->ThrowsErrorLispValnumAngle[(Complexc)]=return$Float$phasecnumAngle[x]=throwError$TypeMismatch"complex number"xnumAnglebadArgList=throwError$NumArgs(Just1)badArgList-- |The nonnegative magnitude of a complex numbernumMagnitude::[LispVal]->ThrowsErrorLispValnumMagnitude[(Complexc)]=return$Float$magnitudecnumMagnitude[x]=throwError$TypeMismatch"complex number"xnumMagnitudebadArgList=throwError$NumArgs(Just1)badArgList-- |Retrieve real part of a complex numbernumRealPart::[LispVal]->ThrowsErrorLispValnumRealPart[(Complexc)]=return$Float$realPartcnumRealPart[x]=throwError$TypeMismatch"complex number"xnumRealPartbadArgList=throwError$NumArgs(Just1)badArgList-- |Retrieve imaginary part of a complex numbernumImagPart::[LispVal]->ThrowsErrorLispValnumImagPart[(Complexc)]=return$Float$imagPartcnumImagPart[x]=throwError$TypeMismatch"complex number"xnumImagPartbadArgList=throwError$NumArgs(Just1)badArgList-- |Take the numerator of the given numbernumNumerator::[LispVal]->ThrowsErrorLispValnumNumerator[n@(Number_)]=returnnnumNumerator[(Rationalr)]=return$Number$numeratorrnumNumerator[(Floatf)]=return$Float$fromInteger.numerator.toRational$fnumNumerator[x]=throwError$TypeMismatch"rational number"xnumNumeratorbadArgList=throwError$NumArgs(Just1)badArgList-- |Take the denominator of the given numbernumDenominator::[LispVal]->ThrowsErrorLispValnumDenominator[Number_]=return$Number1numDenominator[(Rationalr)]=return$Number$denominatorrnumDenominator[(Floatf)]=return$Float$fromInteger$denominator$toRationalfnumDenominator[x]=throwError$TypeMismatch"rational number"xnumDenominatorbadArgList=throwError$NumArgs(Just1)badArgList-- |Convert an exact number to inexactnumExact2Inexact::[LispVal]->ThrowsErrorLispValnumExact2Inexact[(Numbern)]=return$Float$fromIntegernnumExact2Inexact[(Rationaln)]=return$Float$fromRationalnnumExact2Inexact[n@(Float_)]=returnnnumExact2Inexact[n@(Complex_)]=returnnnumExact2Inexact[badType]=throwError$TypeMismatch"number"badTypenumExact2InexactbadArgList=throwError$NumArgs(Just1)badArgList-- |Convert an inexact number to exactnumInexact2Exact::[LispVal]->ThrowsErrorLispValnumInexact2Exact[n@(Number_)]=returnnnumInexact2Exact[n@(Rational_)]=returnnnumInexact2Exact[(Floatn)]=return$Number$roundnnumInexact2Exact[c@(Complex_)]=numRound[c]numInexact2Exact[badType]=throwError$TypeMismatch"number"badTypenumInexact2ExactbadArgList=throwError$NumArgs(Just1)badArgList-- |Convert a number to a string; radix is optional, defaults to base 10num2String::[LispVal]->ThrowsErrorLispValnum2String[(Numbern)]=return$String$shownnum2String[(Numbern),(Numberradix)]=docaseradixof2->do-- Nice tip from StackOverflow question #1959715return$String$showIntAtBase2intToDigitn""8->return$String$printf"%o"n10->return$String$printf"%d"n16->return$String$printf"%x"n_->throwError$BadSpecialForm"Invalid radix value"$Numberradixnum2String[n@(Rational_)]=return$String$shownnum2String[(Floatn)]=return$String$shownnum2String[n@(Complex_)]=return$String$shownnum2String[x]=throwError$TypeMismatch"number"xnum2StringbadArgList=throwError$NumArgs(Just1)badArgList-- |Predicate to determine if given value is a numberisNumber::[LispVal]->ThrowsErrorLispValisNumber([Number_])=return$BoolTrueisNumber([Float_])=return$BoolTrueisNumber([Complex_])=return$BoolTrueisNumber([Rational_])=return$BoolTrueisNumber_=return$BoolFalse-- |Predicate to determine if given number is complex.-- Keep in mind this does not just look at the types isComplex::[LispVal]->ThrowsErrorLispValisComplex([Complex_])=return$BoolTrueisComplex([Number_])=return$BoolTrueisComplex([Rational_])=return$BoolTrueisComplex([Float_])=return$BoolTrueisComplex_=return$BoolFalse-- |Predicate to determine if given number is a real.-- Keep in mind this does not just look at the types isReal::[LispVal]->ThrowsErrorLispValisReal([Number_])=return$BoolTrueisReal([Rational_])=return$BoolTrueisReal([Float_])=return$BoolTrueisReal([Complexc])=return$Bool$(imagPartc)==0isReal_=return$BoolFalse-- |Predicate to determine if given number is a rational.-- Keep in mind this does not just look at the types isRational::[LispVal]->ThrowsErrorLispValisRational([Number_])=return$BoolTrueisRational([Rational_])=return$BoolTrueisRational([n@(Float_)])=return$Bool$isFloatAnIntegern-- FUTURE: not quite good enough, could be represented exactly and not an integerisRational_=return$BoolFalse-- |Predicate to determine if given number is an integer.-- Keep in mind this does not just look at the types; -- a floating point input value can return true, for example.isInteger::[LispVal]->ThrowsErrorLispValisInteger([Number_])=return$BoolTrueisInteger([Complexn])=doreturn$Bool$(isFloatAnInteger$Float$realPartn)&&(isFloatAnInteger$Float$imagPartn)isInteger([Rationaln])=doletnumer=abs$numeratornletdenom=abs$denominatornreturn$Bool$(numer>=denom)&&((modnumerdenom)==0)isInteger([n@(Float_)])=return$Bool$isFloatAnIntegernisInteger_=return$BoolFalse-- |A utility function to determine if given value is a floating point-- number representing an whole number (integer).isFloatAnInteger::LispVal->BoolisFloatAnInteger(Floatn)=(floorn)==(ceilingn)isFloatAnInteger_=False-- - end Numeric operations section ----- |Extract an integer from the given value, throwing a type error if-- the wrong type is passed.unpackNum::LispVal->ThrowsErrorIntegerunpackNum(Numbern)=returnnunpackNumnotNum=throwError$TypeMismatch"number"notNum