from __future__ import (division as _py3_division,
print_function as _py3_print,
absolute_import as _py3_abs_import)
import operator
import sys
from .type_system import Typeclass
from .type_system import is_builtin
from .type_system import nt_to_tuple
from .type_system import build_instance
from .syntax import instance
from .syntax import sig
from .syntax import H
[docs]class Show(Typeclass):
"""Conversion of values to readable strings.
Attributes:
- ``__str__``
- ``show``
Minimal complete definition:
- ``show``
"""
@classmethod
def make_instance(typeclass, cls, show):
__show__ = show ** (H/ "a" >> str)
show = lambda self: __show__(self)
build_instance(Show, cls, {"show": show})
if not is_builtin(cls):
cls.__repr__ = show
cls.__str__ = show
@classmethod
def derive_instance(typeclass, cls):
def show(self):
if len(self.__class__._fields) == 0:
return self.__class__.__name__
nt_tup = nt_to_tuple(self)
if len(nt_tup) == 1:
tuple_str = "(%s)" % Show[nt_tup[0]].show(nt_tup[0])
else:
tuple_str = Show[nt_tup].show(nt_tup)
return "{0}{1}".format(self.__class__.__name__, tuple_str)
Show.make_instance(cls, show=show)
@sig(H/ "a" >> str)
def show(obj):
"""``show :: a -> str``
Convert a value to a readable string.
"""
return Show[obj].show(obj)
[docs]class Eq(Typeclass):
"""The Eq class defines equality (==) and inequality (!=).
Attributes:
- ``__eq__``
- ``__ne__``
Minimal complete definition:
- ``eq``
"""
@classmethod
def make_instance(typeclass, cls, eq, ne=None):
def default_ne(self, other):
return not eq(self, other)
__eq__ = eq ** (H/ "a" >> "a" >> bool)
__ne__ = (default_ne if ne is None else ne) ** (H/ "a" >> "a" >> bool)
eq = lambda self, other: __eq__(self, other)
ne = lambda self, other: __ne__(self, other)
build_instance(Eq, cls, {"eq": eq, "ne": ne})
if not is_builtin(cls):
cls.__eq__ = eq
cls.__ne__ = ne
@classmethod
def derive_instance(typeclass, cls):
def __eq__(self, other):
return self.__class__ == other.__class__ and \
nt_to_tuple(self) == nt_to_tuple(other)
def __ne__(self, other):
return self.__class__ != other.__class__ or \
nt_to_tuple(self) != nt_to_tuple(other)
Eq.make_instance(cls, eq=__eq__, ne=__ne__)
[docs]class Ord(Eq):
"""The Ord class is used for totally ordered datatypes.
Instances of Ord can be derived for any user-defined datatype whose
constituent types are in Ord. The declared order of the constructors in the
data declaration determines the ordering in derived Ord instances. The
Ordering datatype allows a single comparison to determine the precise
ordering of two objects.
Dependencies:
- `Eq`:class:
Attributes:
- ``__lt__``
- ``__le__``
- ``__gt__``
- ``__ge__``
Minimal complete definition:
- ``lt``
"""
@classmethod
def make_instance(typeclass, cls, lt, le=None, gt=None, ge=None):
def_le = lambda s, o: s.__lt__(o) or s.__eq__(o)
def_gt = lambda s, o: not s.__lt__(o) and not s.__eq__(o)
def_ge = lambda s, o: not s.__lt__(o) or s.__eq__(o)
__lt__ = lt ** (H/ "a" >> "a" >> bool)
__le__ = (def_le if le is None else le) ** (H/ "a" >> "a" >> bool)
__gt__ = (def_gt if gt is None else gt) ** (H/ "a" >> "a" >> bool)
__ge__ = (def_ge if ge is None else ge) ** (H/ "a" >> "a" >> bool)
lt = lambda self, other: __lt__(self, other)
le = lambda self, other: __le__(self, other)
gt = lambda self, other: __gt__(self, other)
ge = lambda self, other: __ge__(self, other)
attrs = {"lt": lt, "le": le, "gt": gt, "ge": ge}
build_instance(Ord, cls, attrs)
if not is_builtin(cls):
cls.__lt__ = lt
cls.__le__ = le
cls.__gt__ = gt
cls.__ge__ = ge
@classmethod
def derive_instance(typeclass, cls):
def zip_cmp(self, other, fn):
"""
Compare the data constructor and all of the fields of two ADTs.
"""
if self.__ADT_slot__ == other.__ADT_slot__:
if len(nt_to_tuple(self)) == 0:
return fn((), ())
return fn(nt_to_tuple(self), nt_to_tuple(other))
return fn(self.__ADT_slot__, other.__ADT_slot__)
lt = lambda s, o: zip_cmp(s, o, operator.lt)
le = lambda s, o: zip_cmp(s, o, operator.le)
gt = lambda s, o: zip_cmp(s, o, operator.gt)
ge = lambda s, o: zip_cmp(s, o, operator.ge)
Ord.make_instance(cls, lt=lt, le=le, gt=gt, ge=ge)
[docs]class Bounded(Typeclass):
"""The Bounded class is used to name the upper and lower limits of a
type. Ord is not a superclass of Bounded since types that are not totally
ordered may also have upper and lower bounds.
The Bounded class may be derived for any enumeration type; minBound is the
first constructor listed in the data declaration and maxBound is the last.
Bounded may also be derived for single-constructor datatypes whose
constituent types are in Bounded.
Attributes:
- ``minBound``
- ``maxBound``
Minimal complete definition:
- ``minBound``
- ``maxBound``
"""
@classmethod
def make_instance(typeclass, cls, minBound, maxBound):
attrs = {"minBound": minBound, "maxBound": maxBound}
build_instance(Bounded, cls, attrs)
@classmethod
def derive_instance(typeclass, cls):
# All data constructors must be enums
for data_con in cls.__constructors__:
if not isinstance(data_con, cls):
raise TypeError("Cannot derive Bounded; %s is not an enum" %
data_con.__name__)
maxBound = lambda s: cls.__constructors__[0]
minBound = lambda s: cls.__constructors__[-1]
Bounded.make_instance(cls, minBound=minBound, maxBound=maxBound)
[docs]class Read(Typeclass):
"""Parsing of Strings, producing values.
Attributes:
- ``read``
Minimal complete definition:
- ``read``
"""
@classmethod
def make_instance(typeclass, cls, read):
build_instance(Read, cls, {"read": read})
@classmethod
def derive_instance(typeclass, cls):
Read.make_instance(cls, read=eval)
instance(Show, str).where(show=str.__repr__)
instance(Show, int).where(show=int.__str__)
instance(Show, float).where(show=tuple.__str__)
instance(Show, complex).where(show=complex.__str__)
instance(Show, bool).where(show=bool.__str__)
instance(Show, list).where(show=list.__str__)
instance(Show, tuple).where(show=tuple.__str__)
instance(Show, set).where(show=set.__str__)
instance(Show, dict).where(show=dict.__str__)
instance(Show, frozenset).where(show=frozenset.__str__)
instance(Show, slice).where(show=slice.__str__)
instance(Eq, str).where(eq=str.__eq__, ne=str.__ne__)
instance(Eq, int).where(eq=int.__eq__, ne=int.__ne__)
instance(Eq, float).where(eq=float.__eq__, ne=float.__ne__)
instance(Eq, complex).where(eq=complex.__eq__, ne=complex.__ne__)
instance(Eq, bool).where(eq=bool.__eq__, ne=bool.__ne__)
instance(Eq, list).where(eq=list.__eq__, ne=list.__ne__)
instance(Eq, tuple).where(eq=tuple.__eq__, ne=tuple.__ne__)
instance(Eq, set).where(eq=set.__eq__, ne=set.__ne__)
instance(Eq, dict).where(eq=dict.__eq__, ne=dict.__ne__)
instance(Eq, frozenset).where(eq=frozenset.__eq__, ne=frozenset.__ne__)
instance(Eq, slice).where(eq=slice.__eq__, ne=slice.__ne__)
instance(Eq, type).where(eq=type.__eq__, ne=type.__ne__)
instance(Ord, str).where(lt=str.__lt__, le=str.__le__,
gt=str.__gt__, ge=str.__ge__)
instance(Ord, int).where(lt=int.__lt__, le=int.__le__,
gt=int.__gt__, ge=int.__ge__)
instance(Ord, float).where(lt=float.__lt__, le=float.__le__,
gt=float.__gt__, ge=float.__ge__)
instance(Ord, complex).where(lt=complex.__lt__, le=complex.__le__,
gt=complex.__gt__, ge=complex.__ge__)
instance(Ord, bool).where(lt=bool.__lt__, le=bool.__le__,
gt=bool.__gt__, ge=bool.__ge__)
instance(Ord, list).where(lt=list.__lt__, le=list.__le__,
gt=list.__gt__, ge=list.__ge__)
instance(Ord, tuple).where(lt=tuple.__lt__, le=tuple.__le__,
gt=tuple.__gt__, ge=tuple.__ge__)
instance(Ord, set).where(lt=set.__lt__, le=set.__le__,
gt=set.__gt__, ge=set.__ge__)
instance(Ord, dict).where(lt=dict.__lt__, le=dict.__le__,
gt=dict.__gt__, ge=dict.__ge__)
instance(Ord, frozenset).where(lt=frozenset.__lt__, le=frozenset.__le__,
gt=frozenset.__gt__, ge=frozenset.__ge__)
if sys.version[0] == '2':
instance(Show, long).where(show=long.__str__)
instance(Show, unicode).where(show=unicode.__str__)
instance(Eq, long).where(eq=long.__eq__, ne=long.__ne__)
instance(Eq, unicode).where(eq=unicode.__eq__, ne=unicode.__ne__)
instance(Ord, long).where(lt=long.__lt__, le=long.__le__,
gt=long.__gt__, ge=long.__ge__)
instance(Ord, unicode).where(lt=unicode.__lt__, le=unicode.__le__,
gt=unicode.__gt__, ge=unicode.__ge__)