from __future__ import (division as _py3_division,
print_function as _py3_print,
absolute_import as _py3_abs_import)
import math
import fractions
import sys
from ..lang import data
from ..lang import d
from ..lang import deriving
from ..lang import H
from ..lang import sig
from ..lang import t
from ..lang import instance
from ..lang import build_instance
from ..lang import Enum
from ..lang import Show
from .Eq import Eq
from .Ord import Ord
[docs]class Num(Show, Eq):
"""Basic numeric class.
Dependencies:
- `~hask.lang.typeclasses.Show`:class:
- `~hask.lang.typeclasses.Eq`:class:
Attributes:
- ``__add__``
- ``__mul__``
- ``__abs__``
- ``signum``
- ``fromInteger``
- ``__neg__``
- ``__sub__``
Minimal complete definition:
- ``add``
- ``mul``
- ``abs``
- ``signum``
- ``fromInteger``
- ``negate``
"""
@classmethod
def make_instance(typeclass, cls, add, mul, abs, signum, fromInteger,
negate, sub=None):
@sig(H[(Num, "a")]/ "a" >> "a" >> "a")
def default_sub(a, b):
return a.__add__(b.__neg__())
sub = default_sub if sub is None else sub
attrs = {"add": add, "mul": mul, "abs": abs, "signum": signum,
"fromInteger": fromInteger, "negate": negate, "sub": sub}
build_instance(Num, cls, attrs)
@sig(H[(Num, "a")]/ "a" >> "a")
def negate(a):
"""``signum :: Num a => a -> a``
Unary negation.
"""
return Num[a].negate(a)
@sig(H[(Num, "a")]/ "a" >> "a")
def signum(a):
"""``signum :: Num a => a -> a``
Sign of a number. The functions abs and signum should satisfy the law:
abs x * signum x == x
For real numbers, the signum is either -1 (negative), 0 (zero) or 1
(positive).
"""
return Num[a].signum(a)
@sig(H[(Num, "a")]/ "a" >> "a")
def abs(a):
"""``abs :: Num a => a -> a``
Absolute value.
"""
return Num[a].abs(a)
instance(Num, int).where(
add = int.__add__,
mul = int.__mul__,
abs = int.__abs__,
signum = lambda x: -1 if x < 0 else (1 if x > 0 else 0),
fromInteger = int,
negate = int.__neg__,
sub = int.__sub__
)
try:
instance(Num, long).where(
add = long.__add__,
mul = long.__mul__,
abs = long.__abs__,
signum = lambda x: long(-1) if x < long(0) else (long(1) if x > long(0) else long(0)),
fromInteger = long,
negate = long.__neg__,
sub = long.__sub__
)
except NameError:
pass
instance(Num, float).where(
add = float.__add__,
mul = float.__mul__,
abs = float.__abs__,
signum = lambda x: -1.0 if x < 0.0 else (1.0 if x > 0.0 else 0.0),
fromInteger = float,
negate = float.__neg__,
sub = float.__sub__
)
instance(Num, complex).where(
add = complex.__add__,
mul = complex.__mul__,
abs = complex.__abs__,
signum = lambda x: complex(-1) if x < 0 else complex(1 if x > 0 else 0),
fromInteger = complex,
negate = complex.__neg__,
sub = complex.__sub__
)
[docs]class Fractional(Num):
"""Fractional numbers, supporting real division.
Dependencies:
- `Num`:class:
Attributes:
- ``fromRational``
- ``recip``
- ``__div__``
Minimal complete definition:
- ``fromRational``
- ``div``
"""
@classmethod
def make_instance(typeclass, cls, fromRational, div, recip=None):
if recip is None:
recip = lambda x: div(1, x)
attrs = {"fromRational": fromRational, "div": div, "recip": recip}
build_instance(Fractional, cls, attrs)
Ratio, R =\
data.Ratio("a") == d.R("a", "a") & deriving(Eq)
Rational = t(Ratio, int)
instance(Fractional, float).where(
fromRational = lambda rat: float(rat[0])/float(rat[1]),
div = lambda a, b: float(a)/float(b),
recip = lambda x: 1.0/x
)
@sig(H[(Fractional, "a")]/ "a" >> "a")
def recip(a):
"""``recip :: Fractional a => a -> a``
Reciprocal fraction.
"""
return Fractional[a].recip(a)
[docs]class Floating(Fractional):
"""Trigonometric and hyperbolic functions and related functions.
Dependencies:
- `Fractional`:class:
Attributes:
- ``pi``
- ``exp``
- ``sqrt``
- ``log``
- ``pow``
- ``logBase``
- ``sin``
- ``tan``
- ``cos``
- ``asin``
- ``atan``
- ``acos``
- ``sinh``
- ``tanh``
- ``cosh``
- ``asinh``
- ``atanh``
- ``acosh``
Minimal complete definition:
- ``pi``
- ``exp``
- ``sqrt``
- ``log``
- ``pow``
- ``logBase``
- ``sin``
- ``tan``
- ``cos``
- ``asin``
- ``atan``
- ``acos``
- ``sinh``
- ``tanh``
- ``cosh``
- ``asinh``
- ``atanh``
- ``acosh``
"""
@classmethod
def make_instance(typeclass, cls, pi, exp, sqrt, log, pow, logBase, sin,
tan, cos, asin, atan, acos, sinh, tanh, cosh, asinh, atanh, acosh):
attrs = {"pi": pi, "exp": exp, "sqrt": sqrt, "log": log, "pow": pow,
"logBase": logBase, "sin": sin, "tan": tan, "cos": cos,
"asin": asin, "atan": atan, "acos": acos, "sinh": sinh,
"tanh": tanh, "cosh": cosh, "asinh": asinh, "atanh": atanh,
"acosh": acosh}
build_instance(Floating, cls, attrs)
@sig(H[(Floating, "a")]/ "a" >> "a")
def exp(x):
"""``exp :: Floating a => a -> a``
"""
return Floating[x].exp(x)
@sig(H[(Floating, "a")]/ "a" >> "a")
def sqrt(x):
"""``sqrt :: Floating a => a -> a``
"""
return Floating[x].sqrt(x)
@sig(H[(Floating, "a")]/ "a" >> "a")
def log(x):
"""``log:: Floating a => a -> a``
"""
return Floating[x].log(x)
@sig(H[(Floating, "a")]/ "a" >> "a" >> "a")
def pow(x, y):
"""``pow :: Floating a => a -> a -> a``
"""
return Floating[x].pow(x, y)
@sig(H[(Floating, "a")]/ "a" >> "a" >> "a")
def logBase(x, b):
"""
``logBase :: Floating a => a -> a -> a``
"""
return Floating[x].logBase(x, b)
@sig(H[(Floating, "a")]/ "a" >> "a")
def sin(x):
"""
``sin :: Floating a => a -> a``
"""
return Floating[x].sin(x)
@sig(H[(Floating, "a")]/ "a" >> "a")
def cos(x):
"""
``cos :: Floating a => a -> a``
"""
return Floating[x].cos(x)
@sig(H[(Floating, "a")]/ "a" >> "a")
def tan(x):
"""
``tan :: Floating a => a -> a``
"""
return Floating[x].tan(x)
@sig(H[(Floating, "a")]/ "a" >> "a")
def asin(x):
"""
``asin :: Floating a => a -> a``
"""
return Floating[x].asin(x)
@sig(H[(Floating, "a")]/ "a" >> "a")
def atan(x):
"""
``atan :: Floating a => a -> a``
"""
return Floating[x].atan(x)
@sig(H[(Floating, "a")]/ "a" >> "a")
def acos(x):
"""
``acos :: Floating a => a -> a``
"""
return Floating[x].acos(x)
@sig(H[(Floating, "a")]/ "a" >> "a")
def sinh(x):
"""
``sinh :: Floating a => a -> a``
"""
return Floating[x].sinh(x)
@sig(H[(Floating, "a")]/ "a" >> "a")
def tanh(x):
"""
``tanh :: Floating a => a -> a``
"""
return Floating[x].tanh(x)
@sig(H[(Floating, "a")]/ "a" >> "a")
def cosh(x):
"""
``cosh :: Floating a => a -> a``
"""
return Floating[x].cosh(x)
@sig(H[(Floating, "a")]/ "a" >> "a")
def asinh(x):
"""``asinh :: Floating a => a -> a``
"""
return Floating[x].asinh(x)
@sig(H[(Floating, "a")]/ "a" >> "a")
def atanh(x):
"""
``atanh :: Floating a => a -> a``
"""
return Floating[x].atanh(x)
@sig(H[(Floating, "a")]/ "a" >> "a")
def acosh(x):
"""
``acosh :: Floating a => a -> a``
"""
return Floating[x].acosh(x)
instance(Floating, float).where(
pi = math.pi,
exp = math.exp,
sqrt = math.sqrt,
log = math.log,
pow = pow,
logBase = math.log,
sin = math.sin,
tan = math.tan,
cos = math.cos,
asin = math.asin,
atan = math.atan,
acos = math.acos,
sinh = math.sinh,
tanh = math.tanh,
cosh = math.cosh,
asinh = math.asinh,
atanh = math.atanh,
acosh = math.acosh
)
[docs]class Real(Num, Ord):
"""Real numbers.
Dependencies:
- `Num`:class:
- `~hask.lang.typeclasses.Ord`:class:
Attributes:
- ``toRational``
Minimal complete definition:
- ``toRational``
"""
@classmethod
def make_instance(typeclass, cls, toRational):
build_instance(Real, cls, {})
@sig(H[(Real, "a")]/ "a" >> Rational)
def toRational(x):
"""``toRational :: Real a => a -> Rational``
Conversion to Rational.
"""
return Real[x].toRational(x)
[docs]class Integral(Real, Enum):
"""Integral numbers, supporting integer division.
Dependencies:
- `Real`:class:
- `~hask.lang.lazylist.Enum`:class:
Attributes:
- ``quotRem``
- ``toInteger``
- ``quot``
- ``rem``
- ``div``
- ``mod``
Minimal complete definition:
- ``quotRem``
- ``toInteger``
- ``quot``
- ``rem``
- ``div``
- ``mod``
"""
@classmethod
def make_instance(typeclass, cls, quotRem, divMod, toInteger, quot=None,
rem=None, div=None, mod=None):
quot = lambda x: quotRem(x)[0] if quot is None else quot
rem = lambda x: quotRem(x)[1] if rem is None else rem
div = lambda x: divMod(x)[0] if div is None else div
mod = lambda x: divMod(x)[1] if mod is None else mod
attrs = {"quotRem": quotRem, "toInteger": toInteger, "quot": quot,
"rem": rem, "div": div, "mod": mod, "divMod": divMod}
build_instance(Integral, cls, attrs)
@sig(H[(Integral, "a")]/ "a" >> "a" >> t(Ratio, "a"))
def toRatio(num, denom):
"""``toRatio :: Integral a => a -> a -> Ratio a``
Conversion to Ratio.
"""
frac = fractions.Fraction(num, denom)
return R(frac.numerator, frac.denominator)
instance(Real, int).where(
toRational = lambda x: toRatio(x, 1)
)
try:
instance(Real, long).where(
toRational = lambda x: toRatio(x, 1)
)
except NameError:
pass
instance(Real, float).where(
toRational = lambda x: toRatio(round(x), 1) # obviously incorrect
)
instance(Integral, int).where(
quotRem = lambda x, y: (x / y, x % y),
toInteger = int,
quot = lambda a, b: int(a)/int(b),
rem = int.__mod__,
div = lambda a, b: int(a)/int(b),
mod = int.__mod__,
divMod = divmod
)
try:
instance(Integral, long).where(
quotRem = lambda x, y: (x / y, x % y),
toInteger = int,
quot = long.__div__,
rem = long.__mod__,
div = long.__div__,
mod = long.__mod__,
divMod = divmod
)
except NameError:
pass
[docs]class RealFrac(Real, Fractional):
"""Extracting components of fractions.
Dependencies:
- `Real`:class:
- `Fractional`:class:
Attributes:
- ``properFraction``
- ``truncate``
- ``round``
- ``ceiling``
- ``floor``
Minimal complete definition:
- ``properFraction``
- ``truncate``
- ``round``
- ``ceiling``
- ``floor``
"""
@classmethod
def make_instance(typeclass, cls, properFraction, truncate, round, ceiling,
floor):
attrs = {"properFraction": properFraction, "truncate": truncate,
"round": round, "ceiling": ceiling, "floor": floor}
build_instance(RealFrac, cls, attrs)
@sig(H[(RealFrac, "a"), (Integral, "b")]/ "a" >> ("b", "a"))
def properFraction(x):
"""``properFraction :: RealFrac a, Integral b => a -> (b, a)``
The function properFraction takes a real fractional number x and returns a
pair (n,f) such that x = n+f, and:
n is an integral number with the same sign as x; and
f is a fraction with the same type and sign as x, and with absolute
value less than 1.
"""
return RealFrac[x].properFraction(x)
@sig(H[(RealFrac, "a"), (Integral, "b")]/ "a" >> "b")
def truncate(x):
"""``truncate :: RealFrac a, Integral b => a -> b``
truncate(x) returns the integer nearest x between zero and x
"""
return RealFrac[x].truncate(x)
@sig(H[(RealFrac, "a"), (Integral, "b")]/ "a" >> "b")
def round(x):
"""``round :: RealFrac a, Integral b => a -> b``
round(x) returns the nearest integer to x; the even integer if x is
equidistant between two integers
"""
return RealFrac[x].round(x)
@sig(H[(RealFrac, "a"), (Integral, "b")]/ "a" >> "b")
def ceiling(x):
"""``ceiling :: RealFrac a, Integral b => a -> b``
ceiling(x) returns the least integer not less than x
"""
return RealFrac[x].ceiling(x)
@sig(H[(RealFrac, "a"), (Integral, "b")]/ "a" >> "b")
def floor(x):
"""``floor :: RealFrac a, Integral b => a -> b``
floor(x) returns the greatest integer not greater than x
"""
return RealFrac[x].floor(x)
instance(RealFrac, float).where(
properFraction = lambda x: (int(math.floor(x)), x - math.floor(x)),
truncate = lambda x: int(math.floor(x) if x > 0 else math.floor(x+1)),
round = lambda x: int(round(x, 0)),
ceiling = math.ceil,
floor = math.floor
)
[docs]class RealFloat(Floating, RealFrac):
"""Efficient, machine-independent access to the components of a
floating-point number.
Dependencies:
- `Floating`:class:
- `RealFrac`:class:
Attributes:
- ``floatRange``
- ``isNan``
- ``isInfinite``
- ``isNegativeZero``
- ``atan2``
Minimal complete definition:
- ``floatRange``
- ``isNan``
- ``isInfinite``
- ``isNegativeZero``
- ``atan2``
"""
@classmethod
def make_instance(typeclass, cls, floatRange, isNan, isInfinite,
isNegativeZero, atan2):
attrs = {"floatRange": floatRange, "isNan": isNan,
"isInfinite": isInfinite, "isNegativeZero": isNegativeZero,
"atan2": atan2}
build_instance(RealFloat, cls, attrs)
@sig(H[(RealFloat, "a")]/ "a" >> bool)
def isNaN(x):
"""``isNaN :: RealFloat a => a -> bool``
True if the argument is an IEEE "not-a-number" (NaN) value
"""
return RealFloat[x].isNan(x)
@sig(H[(RealFloat, "a")]/ "a" >> bool)
def isInfinite(x):
"""``isInfinite :: RealFloat a => a -> bool``
True if the argument is an IEEE infinity or negative infinity
"""
return RealFloat[x].isInfinite(x)
@sig(H[(RealFloat, "a")]/ "a" >> bool)
def isNegativeZero(x):
"""``isNegativeZero :: RealFloat a => a -> bool``
True if the argument is an IEEE negative zero
"""
return RealFloat[x].isNegativeZero(x)
@sig(H[(RealFloat, "a")]/ "a" >> "a" >> "a")
def atan2(y, x):
"""``atan2 :: RealFloat a => a -> a -> a``
a version of arctangent taking two real floating-point arguments
"""
return RealFloat[x].atan2(y, x)
instance(RealFloat, float).where(
floatRange=(sys.float_info.min, sys.float_info.max),
isNan=math.isnan,
isInfinite=lambda x: x == float('inf') or x == -float('inf'),
isNegativeZero=lambda x: math.copysign(1, x) == -1.0,
atan2=math.atan2
)