/*preamble

    chiron src/base.js
    
    Copyright (c) 2002-2008 Kris Kowal <http://cixar.com/~kris.kowal>
    MIT License
    
    The license terms are stated in full in <license.rst> and at the end
    of all source files.

*/

/*status works passes tests in Firefox 2, Safari 2 and 3, and Explorer 6 */
/*quality .8 */
/*step 2 */

/**
    Builds on `boot.js`, providing a type system,
    base types, and base functions covering iteration,
    collections, and type-insensitive operators.

    Provides:

     - a type system

      - class inheritance
      - multiple inheritance
      - mixins
      - linear method resolution order
      - polymorphism including super-type
        implementations of methods
      - encapsulation: public and private, methods
        and data, using closures and context objects
      - callable instances

     - iteration

      - an `Iter` type for creating raw iterations from
        a `next` function and the `StopIteration` exception

      - a polymorphic, type-insensitive `iter` that can
        iterate on `Object`, `Array`, `String`,
        `Set`, `Dict`, `List`, `Range`, `Sequence`
        and any type that provides a custom `iter` method.

      - an `Iterable` mixin that adds convenient functions

       - a host of functions for manipulating iterations including
         `forEach`, `each`, `where`, `zip`, `transpose`,
         `enumerate`, `reduce`, `cycle`, `flatten`,
         `compact`, `without`, `group`, `sort`, `add`,
         `min`, `max`, `sum`, `product`,
         `any`, `all`, `join`, and type-conversions,
         lazy, stateless, and variadic versions of the
         above as appropriate.

       - all iterables are callable, so they can be used
         as a relation function, mapping their domain of keys 
         to their range of values.

     - base types: `List`, `Dict`, `Set`, `Range`,
       `Iterable`, `Iter`, and `Base`

       - sets and dictionaries improve upon the use of native
         JavaScript objects by opening range of values and
         domain of keys to all JavaScript objects instead of
         merely some strings.  These types use a `hash`
         function to map objects to string hash keys and
         prefixed with a tilde internally to prevent any
         collisions with native `Object` members like
         ``__proto__`` or ``toValue``.  All instances of
         `Base` (all types defined with this module's
         type system) implicitly have a random hash string.
       - dictionaries are sets of items (key value pairs)
         hashed and compared by their key instead of the item.
       - lists improve upon native `Array` by providing
         lots of member functions and the full dictionary
         interface.  Lists also implicitly optimize sorts
         if you use a comparator provided by the `by`
         function, nearly doubling their performance with
         a Schwartzian transform.
       - ranges are lazy collections of numbers inside an
         interval on a stride.  Ranges are iterable and
         support most list operations including a fast
         function for testing whether a range `has` a 
         particular value.

     - base functions

       - iteration: many names mentioned already, but also `map`,
         `times`, and `repeat`
       - type conversions: `number`, `bool`, `list`,
         `dict`, `set`, `array`, `object`, `string`,
         `as`, `to`
       - types: `getType`, `getTypeName`, `getTypeFullName`
       - arithmetic operators: `add`, `sub`, `mul`,
         `div`, `sum`, `product`
       - logic operators: `and`, `or`, `not`
       - comparison: `eq`, `lt`, `ne`, `le`, `gt`,
         `ge`, `by`, `compare`, `desc`
       - set operations: `unique`, `hash`, `eq`
       - dictionary operators: `get`, `set`, `has`, `del`,
         `hasKey`, `hasValue`, `update`, `complete`,
         `clear`, `keys`, `values`, `items`
       - list operators: `has`, `getLength`, `reversed`,
         `sorted`, `sliced`, `join`, `first`, `last`,
         `begins`, `ends`
       - string operators: `trim`, `trimBegin`, `trimEnd`,
         `padBegin`, `padEnd`, `split`, `enquote`,
         `expand`
       - ranges: `count`, `range`
       - functions: `args`, `invoke`, `partial`
       - introspection: `dir`, `repr`, `help`
       - utilities: `index`, `member`, `schedule`,
         `inherit`, `pass`


    Idioms
    ======

     - tolerance of input: functions provide behaviors for all
       meaningful types, including native JavaScript `Object`
       (which are promoted to dictionaries or lists of pairs),
       `Arrays` (which are promoted to lists), `String`, and
       other types that define custom behaviors with polymorphic
       function overload.
     - strictness of output: functions return the most powerful type
       appropriate for their behavior, usually `List`, `Dict`,
       or `Set` instances.  `Array` objects are occasionally used
       like tuples in Python.
     - flexibility: all complex types are easily convertable
       to native JavaScript `Object`, `Array`, and
       `String` instances.
     - laziness: any function that would consume an iteration
       also provides an equivalent lazy implementation that
       returns an iteration that would incrementally consume
       the original iteration to provide each item.  To use
       the lazy version of a greedy function, add `iter` as
       the last term of its name.
     - polymorphism: functions defer to custom 
       polymorphic implementations.
     - currying: to ease the creation of lambdas, or anonymous
       functions, many functions will curry if less than a
       minimum number of arguments are provided.  The curried
       function accepts an object to operate on.
     - copying: all types accept an optional object to shallowly
       copy as theif first argument.
     - conversion: all collection types form conversion rings.
       That is, any collection or iteration can be converted 
       to any other collection type and converted back
       to the same type using the copy constructor.
     - state: many functions distinguish between in-place
       and stateless variants.
   

    Names
    =====

    Most names have been chosen for easy migration from Python.
    Some names from other languages snuck in when they were
    simply more meaningful or filled a void Python left.  All
    names conform to Chiron JavaScript's case conventions
    and avoid the use of superfluous underscores.

    Different than Python:
     - ``strip``: `trim`
     - ``lstrip``: `trimBegin`
     - ``rstrip``: `trimEnd`
     - ``len``: `getLength`
     - ``contains``: `has`
     - ``in``: `has` (reverse argument order)
     - ``__*item__``: `*`
       for `get`, `has`, `set`, `del`, `put`
       (where applicable)
     - ``__call__``: `invoke`
     - ``filter``: `where` (`filter` has the opposite semantic in English)

    Different than Prototype:
     - ``clone``: `copy`
     - ``collect``: only `each`
     - ``detect``: use `dropWhile` and `next` from `boost.js`
     - ``eachSlice``: `pools` in `boost.js`
     - ``entries``: `array`
     - ``findAll``: `where`
     - ``grep``: `where`
     - ``inGroupsOf``: `pools` in `boost.js`
     - ``include``: `has`
     - ``inspect``: `repr`
     - ``invoke``: `each` with `member` (``invoke`` is ``call`` without ``context``)
     - ``map``: varies from `each` by argument order.  not a member of `Iterables`
     - ``member``: `has`
     - ``partition``: use `group` (returns `Dict`)
     - ``pluck``: `each` with `item`
     - ``select``: `where`
     - ``size``: `getLength`
     - ``sortBy``: use `sort` and `by`
     - ``toArray``: `array`
     - ``toJSON``: `json` in `json.js`
     - ``uniq``: `unique`

    ``base.js`` includes everything you would expect in
    Python's ``itertools`` module.  There are, however, some
    differences of nomenclature and nuances of design:

     - `chain`: same
     - ``count``: `getLength`.  `count` actually provides an
       iterator on counting numbers
     - `cycle`: same
     - ``dropwhile``: `dropWhile` in `boost.js`
     - ``groupby``: try `group` and `by`
     - ``ifilter``: try `whereIter`
     - ``ifilterfalse``: try `whereIter`, `compose`, and `not`
     - ``imap``: try `eachIter`
     - ``islice``: try `sliceIter`
     - ``izip``: try `zipIter`
     - `repeat`: same
     - ``starmap``: try `eachArgs` or `eachArgsIter`.  ``starmap``,
       while being more terse of a name, uses "star" to imply a hint on the
       Python-specific variadic argument syntax.  In JavaScript,
       Function.apply provides variadic arguments on each item of an
       iteration.
     - ``takewhile``: try `takeWhile`
     - `tee`: same

*/

include('environment.js');
publish(require('boot.js'));

/**
    Types
    =====
*/

/*** type
    returns a new, mixable, callable, type object for
    a type that inherits from an optional array or list
    of base types and a constructor function.

    ``type(functor)`` or
    ``type(bases, functor)``

    All types implicitly inherit from `Base`.  When
    you create a type, the type function linearizes your
    inheritance tree to produce a "method resolution
    order" (MRO).  `Base` is always the last type in the
    MRO, and the returned type object is always
    the first type in the MRO.  The linearization
    algorithm is the same as that for Python's new-style
    classes and does not permit ambiguity in the order
    of base types.  `type` will throw a `TypeError`
    if you attempt to construct a type from bases
    that have the same ancestors in different orders.
    The method resolution order algorithm is similar
    to a topological sort, which only works for
    trees, that is, graphs with no cycles.

    Type objects are functions that, when called, 
    produce instances of that type.  You can not
    use the ``new`` operator, and type objects are
    accepted anywhere functions are called.

    When you construct an instance, you effectively
    get a new Function object (so that all instances
    can also be callable) that has been decorated
    in layers by the constructor functions of all of
    the super-types in its MRO, from bottom (`Base`)
    to top.  Then, your new instance's `init`
    function gets called with the same arguments
    you provided to the type function.

    If a type overloads a function from a super-type,
    you can access a "snapshot" of the `type`
    after that super-type's constructor ran using
    the ``getSuper(SubType)`` method.  `getSuper`
    requires that you specify the type you're calling
    from since types are mixable and your immediate
    super-type is not necessarily the first 
    type in your list of bases.

    You can define the an instance's function
    call behavior by defining an `invoke` method
    that will receive the arguments and return
    its result.  This is analogous to defining
    ``__call__`` in Python.

*/
this.type = foreignModuleBind(function () {

    var module = this;
    var moduleScope = module.moduleScope;

    var bases;
    var construct;
    var name;
    var count = 0;

    if (arguments.length == 0) {
        bases = [];
        construct = pass;
    } else if (arguments.length == 1) {
        bases = [];
        construct = arguments[0];
    } else if (arguments.length == 2) {
        bases = arguments[0];
        construct = arguments[1];
    } else {
        throw TypeError("Invalid type declaration");
    }

    /* if the constructor is an object instead of a function,
     * transform the constructor into a function that copies
     * the members of the object into the given layer */
    if (!(construct instanceof Function)) {
        construct = (function (construct) {
            return function () {
                return update(this, construct);
            };
        }).call(this, construct);
    }

    /* if the base type were specified dynamically using a List
     * or some such object, convert them to an array */
    if (!(bases instanceof Array)) {
        bases = bases.to(array);
    }

    /* create a type function.  this is a function that
     * returns new instances of the type and carries the type's
     * member functions */
    var self = function () {

        var layers = {};

        /* create an instance function.  this function
         * defers to a user-defined "invoke" function and
         * carries the public interface of the instance. */
        var instance = Instance(self, layers);

        /* establish a set of instances for each type in the mro */
        arrayEach(arrayReversed(mro), function (baseType) {
            baseType.getConstruct().call(instance);
            layers[baseType.getFullName()] = Layer(
                instance,
                layers,
                baseType
            );
        });

        instance.init.apply(instance, arguments);

        return instance;
    };

    var alias = aliaser(self);

    /**** constructor
        a reference to `type` so that types can be
        identified as "instances" of type.  This is an
        implementation detail that powers `repr` in its
        ability to represent types, and the `isInstance`
        ability to identify them.
    */
    self.constructor = type;

    /**** getName
        returns the name of the type as it was declared
        in its originating module.  If the type was
        not declared publically in its originating module
        (attributed to the module object), returns
        a number that is guaranteed to be the same
        for all instances of the same type as long
        as a module remains loaded.

        `getName` will return either a `String` or
        a `Number`.

        The first time `getName` is called, it searches
        for the type's name in its declaring
        module.  Failing that, it assigns a number
        to the type.  `getName` then redefines
        itself so that it returns the same name
        to all future calls.
    */
    self.getName = function () {

        /* scan the containing module for a name
         * for this type */
        for (var key in module) {
            var value = module[key];
            if (value === self) {
                name = key;
            }
        }

        /* if there was no name in the module, the type
         * is anonymous.  give the type a hearty new
         * number for a name. */
        if (no(name)) {
            if (no(moduleScope.annonymousTypeCount)) {
                moduleScope.annonymousTypeCount = 0;
            }
            name = moduleScope.annonymousTypeCount++;
        }

        /* cheap cache */
        self.getName = function () {return name;};

        return name;
    };

    /**** getFullName
        the `moduleUrl` (relative to `modulesUrl`)
        of the declaring module with the name of the
        type in the anchor (following ``#``).
    */
    self.getFullName = function () {
        return (moduleScope.moduleUrl || '') + '#' + self.getName();
    };

    /**** getModule
        the module object for the module that the
        type was declared in.
    */
    self.getModule = function () {
        return module;
    };

    /**** getModuleScope
        the modules scope of the module that the
        type was declared in.
    */
    self.getModuleScope = function () {
        return moduleScope;
    };

    /**** isType
        returns whether this type is or inherits
        from another type.
    */
    self.isType = function (otherType) {
        return arrayAny(arrayEach(mro, function (baseType) {
            return baseType === otherType;
        }));
    };

    /**** getBases
        returns a `List` of `type` objects for
        this type's immidiate super-types.
    */
    self.getBases = function () { return List(bases); };

    /**** getBasesArray
        `getBases` but returns a native `Array`
        instead of a `List`.

        an internal function used by the type system to
        construct types using native arrays since
        List may not have been defined yet or causes
        infinite recursion.
    */
    self.getBasesArray = function () { return copy(bases); };

    /**** getMro
        returns a `List` including the transitive closure
        of this type and each member's super-types in their
        order of precedence.  Thus, this type is always the
        first element, and `Base` is always the last.
    */
    self.getMro = function () { return List(mro); };

    /**** getMroArray
        `getMro` but returns a native `Array` 
        instead of a `List`.

        an internal function used by the type system to
        construct types using native arrays since
        List may not have been defined yet or causes
        infinite recursion.
    */
    self.getMroArray = function () { return copy(mro); };

    /**** getConstruct
        Returns the constructor function for this `type`.
        When a new instance is created, all of the constructor
        functions in members of this type's method resolution
        order are applied to the new instance `Function`
        object in reverse order, so `Base`'s constructor
        runs first, and the return value of `getConstruct`
        is applied last.
    */
    self.getConstruct = function () { return construct; };

    /**** repr
        prints a representation of the type.
    */
    self.repr = function () {
        return '<type ' + self.getFullName() + '>';
    };

    /**** string
        alias of `repr` by default.
    */
    self.string = alias('repr');

    /**** toString
        alias of `repr` by default.
    */
    self.toString = alias('repr');

    /**** nextHash
        returns a unique hash for an instance.
    */
    self.nextHash = function () {
        return count++;
    };

    /* calculate the method resolution order */
    var mro = getMro(self);

    return self;
});

/*
    construct a monotonic method resolution order for a given type [#mro]_.
    An internal function of the type system modeled after Python's
    method resolution order calculation.
*/
/*todo consider improving the brevity, performance, and elegance
 * of this algorithm after an exhaustive test suite is ready */
var getMro = function (type) {
    var merge = function (rows) {
        var result = [];
        while (true) {
            var nonEmptyRows = arrayWhere(rows, function (row) {
                return row.length > 0;
            });
            if (nonEmptyRows.length === 0) {
                return result;
            }
            var candidate = null;
            arrayEach(nonEmptyRows, function (row) {
                candidate = row[0];
                if (
                    arrayAny(arrayEach(nonEmptyRows, function (row) {
                        return arrayHas(arraySliced(row, 1), candidate);
                    }))
                ) {
                    candidate = null;
                } else {
                    throw stopIteration;
                }
            });
            if (!candidate) {
                throw TypeError("Inconsistent hierarchy");
            }
            result.push(candidate);
            arrayEach(nonEmptyRows, function (row) {
                if (row[0] === candidate) {
                    row.shift();
                }
            });
        }
        return result;
    };

    try {
        var basesArray = arrayAdded(
            [[type]],
            arrayEach(type.getBasesArray(), function (baseType) {
                return baseType.getMroArray();
            }),
            [type.getBasesArray()]
        );
        if (module.Base) {
            basesArray = arrayAdded(
                basesArray,
                [[Base]]
            );
        }
        return merge(basesArray);
    } catch (exception) {
        if (exception instanceof TypeError) {
            throw TypeError(
                "Inconsistent hierarchy for " + 
                enquote(type.getName()) + "."
            );
        } else {
            throw exception;
        }
    }

};

/*** Undefined
    A constructor for the `undefined` constant.

    The value `undefined` is not a member of the type system,
    but for orthogonality, we provide an `Undefined` type.
    This feature preserves the following identities:

     - ``isInstance(undefined, Undefined)``
     - ``getType(undefined) === Undefined``
     - ``getType(undefined)() === undefined``
     - ``getTypeName(undefined) === 'Undefined'``
*/

this.Undefined = function () {
    return undefined;
};

/*** Null
    A constructor for the `null` constant, analgous
    to `Undefined`.
*/
this.Null = function () {
    return null;
};

/*** Base
    All instances returned by types return by `type`
    inherit from `Base`.  `Base` provides functions
    that all instances implement with some default
    behavior.
*/

/*
    These, Instance and Layer, are internal functions of the
    type system but carry some of the inital properties of
    all instances and so their members are appropriately
    documented with the Base type.
*/
var Instance = function (type, layers) {

    /*
        to make possible the idea that objects should be callable 
        and be able to override callability, the "dictionary" object
        for the instance is actually a function.  This function
        only exists to call the instance's invoke method.
    */
    var instance = function () {
        return instance.invoke.apply(instance, arguments);
    };

    /**** getType
        returns the type function object that created this
        instance.
    */
    instance.getType = function () {
        return type;
    };

    /**** getSuper
        accepts a type and returns next type
        in this instance's method resolution order.
        This is not guaranteed to be the instance
        that immediately succeeds the given type in the
        list of `Base` types provided to the
        current type's definition since mix-in
        style objects can sandwich types in between.
    */
    instance.getSuper = function (Type) {
        if (no(Type)) {
            throw TypeError(
                "getSuper requires an argument for the " +
                "type you're trying to get the supertype of."
            );
        }
        var mro = type.getMroArray();
        var index = arrayFind(mro, Type) + 1;
        if (index >= mro.length) {
            throw TypeError(
                type.getName() + ' does not extend ' +
                Type.getName()
            );
        }
        return layers[mro[index].getFullName()];
    };

    /**** as
        Coerces this instance into an instance of
        a given type.  If the other type is a member of
        this instance's ancestor types, returns itself.
        Otherwise, uses the `to` member function
        to create a new object based on this one.
    */
    instance.as = function (otherType) {
        if (
            otherType.getFullName &&
            layers[getotherType.getFullName()]
        ) {
            return instance;
        } else {
            return instance.to(otherType);
        }
    };

    return instance;
};

/* a layer is an object that contains all of the interface
 * functions defined for an instance as its built up to
 * a given base type */
var Layer = function (instance, layers, type) {

    var layer = function () {
        return layer.invoke.apply(instance, arguments);
    };

    /* bind all functions of the layer to the instance */
    for (var key in instance) {
        var value = instance[key];
        /* layers only carry functions */
        /*todo review */
        if (value instanceof Function) {
            layer[key] = bind(instance, instance[key]);
        }
    }
    
    return layer;

};

this.Base = type(function () {
    var self = this;
    var alias = aliaser(self);

    /* the hash key is a string containing the mantissa
     * of a random number */
    var hashKey = this.getType().nextHash();

    /**** init
        an empty initializer so that all derived types can
        safely assume that ``this.getSuper(AnyType).init()``
        will work.
    */
    self.init = function () {
    };

    /**** isInstance
        returns whether a given type is one of
        this instance's type or any of its 
    */
    self.isInstance = function (otherType) {
        return self.getType().isType(otherType);
    };

    /**** getTypeName
        returns the name of this instance's type.
    */
    self.getTypeName = function () {
        return self.getType().getName();
    };

    /**** getTypeFullName
        returns the full name of this instance's type.
    */
    self.getTypeFullName = function () {
        return self.getType().getFullName();
    };

    /**** repr
        returns a `String` representation of the
        instance for debugging purposes.
    */
    self.repr = self.string = function () {
        return '<instance ' + self.getTypeFullName() +
            ' ' + hashKey + '>';
    };

    /**** string
        an alias of `repr` by default.
    */
    self.string = alias('repr');

    /**** hash
        provides a default, random hash to identify 
        the instance.
    */
    self.hash = function () {
        return hashKey + self.getTypeName();
    };

    /**** eq
        returns whether this instance is equivalent
        to another instance.  Overrided forms of
        `eq` should perform a deep comparison.
        The default behavior is ``this === that``,
        which returns whether they are exactly
        the same object in memory.
    */
    self.eq = function (other) {
        return self === other;
    };

    /**** ne
        returns whether an object is not equal to
        another, deferring to `eq` if not
        overridden.
    */
    self.ne = function (other) {
        return !self.eq(other);
    };

    /**** string
        converts the instance to a string.  The
        default behavior provided by `Base` is
        to defer to `repr`.
    */
    self.string = alias('repr');

    /**** bool
        a default implementation that always
        returns `true`.
    */
    self.bool = function () {
        return true;
    };

    /**** not 
        defers to the logical negation of `bool`.
    */
    self.not = function () {
        return !self.bool();
    };

    /**** toString
        defers to `string`.  Provided so that native
        JavaScript functions gain the benefits of derived
        types with `string` type functions.
    */
    self.toString = alias('repr');

    /**** copy
        returns a shallow copy of this object.  The
        default behavior is to defer to the 
        constructor, passing this instance as an
        argument to `init`.
    */
    self.copy = function () {
        return self.getType()(self);
    };

    /**** to
        calls a given function with this object as an argument
        and returns the result.  this is similar to `as`
        except that it's guaranteed to return a new copy
        of the object.
    */
    self.to = function () {
        /* modules.js#include provides these names to functions
         * that were included from another module */
        var args = array(arguments);
        var functor = args.shift();
        if (self[getTypeFullName(functor)])
            return self[getTypeFullName(functor)].apply(self, args);
        if (self[getTypeName(functor)])
            return self[getTypeName(functor)].apply(self, args);
        return functor.apply(self, [self].concat(args));
    };

    /*** given
        applies a stateful function on itself and returns
        itself.  This function may not exist in future versions,
        `given` its limited utility.
    */
    self.given = function (functor) {
        functor.call(self, self);
        return self;
    };

});

/*** operator

     * returns a currying polymorphic operator.
     * accepts a minimum number arguments for full application.
     * accepts a member function name for the polymoprhic equivalent,
       e.g., "added" for "add", "list" for "list".
     * accepts a functor to call if the given object does not override
       the named function.

    The returned operator will curry once if fewer arguments are supplied
    than the requested minimum.  this function will accept one argument,
    the object to apply on, reapply the operator with the given object
    as the first argument and previously given arguments following, and
    return the result.  Thus::

        set("key", "value")(object)

    is equivalent to::

        set(object, "key", "value")

    Since `set` is defined as a polymorphic currying operator::

        this.set = operator(3, "set", function (object, key, value) {
            ...
        });
        
*/
this.operator = function (n, name, functor) {
    var result = function (object) {
        /* curry if only one argument */
        var self = this;
        if (arguments.length < n) {
            var args = array(arguments);
            /* curry on the arguments following the first
             * so that gt(10)(x) means x > 10,
             * and set("a", 10") means set(o, "a", 10) */
            return function (object) {
                return result.apply(self, [object].concat(args));
            };
        }
        if (isInstance(object, Base) && object[name])
            return object[name].apply(object, arraySliced(arguments, 1));
        /* i decided NOT to put special logic for function composition here
         * (like add(f, g) == \x add(f(x), g(x))) because it would cause
         * existing code to break where Function objects were being
         * treated as real Objects for operations like update, complete,
         * dir &c.  might as well be explicit about composition anyway;
         * i'm sure there's a better way even though implicit would be
         * most terse. */
        return functor.apply(this, arguments);
    };
    /* it is necessary to name the function
     * so it's accessible for the curry */
    return result;
};

/*** method
    returns a method based on the name of a function
    provided in the module that `method` is called
    in.  The module function should accept the
    method's context object as its first argument.
*/
this.method = foreignModuleBind(function (functor) {
    var module = this;
    return function () {
        return functor.apply(
            module,
            [this.valueOf()].concat(array(arguments))
        );
    };
});

/*** isInstance
    returns whether a given object is an instance of the
    given type.  Works for both native prototype inheritance
    and `type` inheritance.
    currys a partial operator if less than 2 arguments are provided.
    
    Works for boxed types::

        isInstance(1, Number)
        isInstance(Number(1), Number)
        isInstance(new Number(1), Number)
    
    Considers `Arguments` objects to be `Arrays`::

        isInstance(arguments, Array)

    Only reports that `type` instances are `Function`
    objects if they implement `invoke`.

*/
this.isInstance = function (value, type) {
    if (value === undefined) return type === Undefined;
    if (value === null) return type === Null;

    if (no(type))
        return function (x) {
            return isInstance(x, value);
        };

    if (typeof value == 'function' && type == Function) {
        if (value.isInstance)
            return value.invoke && value.invoke != Function.prototype.invoke;
            /* since our instances and functions are really Functions,
             * only admit to being functions if 'invoke' is implemented */
        return !(value instanceof RegExp);
        /* don't admit that regular expressions are objects since they
         * don't implement call or apply, boo */
    }

    /* necessary to catch string literals */
    if (value.constructor === type) return true;

    /* http://ajaxian.com/archives/working-aroung-the-instanceof-memory-leak */
    if (!value.valueOf) return false;

    if (value instanceof type) return true;

    /* treat Arguments as Arrays [#arguments]_. */
    if (value.callee && type === Array) return true;

    /* some arrays appear to be undetectable */
    //if (value.length !== undefined && type === Array) return true;

    if (typeof value == 'number' || typeof value == 'NaN') 
        return type === Number;

    /* catch isInstance(module, Object)? to avoid infinite recursion */
    if (value.isInstance === isInstance) 
        return type === Object;

    if (value.isInstance) 
        return value.isInstance(type);

    return false;
};

/*** getType
    returns a type object for a given instance.

    `getType`, or the Chiron environment in general,
    attempts to support several idioms.  Foremost,
    `isInstance` and `getType` should cooperate to
    guarantee this axiom::

        isInstance(instance, getType(instance))

    `getType` should also return a constructor and
    copy constructor "factory method" for the instance's
    type::

        isInstance(getType(instance)(), getType(instance))
        eq(getType(instance)(instance), instance)

    These axioms are posed by Chiron types, in so far
    as implementors of Chiron types choose to support them.
    JavaScript native types do not make such guarantees.
    This is a leaky abstraction.

    However, these axioms work even in some odd edge-cases
    that wouldn't otherwise be supported by native
    JavaScript.  For example, the types of `undefined`
    and `null` are this module's `Undefined` and `Null`
    constructor functions.  `isInstance` recognizes
    these types, and calling these types as constructors
    or copy constructors returns their respective instance.

    `Array` instances return the `array` function instead
    of the `Array` constructor.  `array` actually serves
    as a copy constructor instead of the highly overloaded,
    variadic `Array` constructor.  `isInstance` cooperates
    by indicating that `Array` instances do in fact
    instantiate from `array`.  This constructor can also
    construct an `Array` from any iterable.

    Objects that are plain `Object` instances (not
    instances of derrived prototypes) return `object`
    instead of the `Object` constructor.  `isInstance`
    cooperates in the same way as arrays.  The `object`
    function can construct objects from any iterable.

*/
this.getType = function (value) {
    if (value === undefined) return Undefined;
    if (value === null) return Null;
    if (isInstance(value, Base) && value.getType) try {
        return value.getType();
    } catch (exception) { }
    if (isInstance(value, Array)) return array;
    if (value.constructor == Object) return object;
    return value.constructor;
};

/*** getTypeName
    returns the name of an instance's type with due
    dilligence.

    Since this function behaves differently
    in nearly ever environment and certain names
    are not exported by modules in various circumstances,
    its return values are purely informational.
*/
this.getTypeName = function (value) {
    if (value === undefined) return 'Undefined';
    if (value === null) return 'Null';
    if (value.getTypeName) return value.getTypeName();
    if (value['modules.js#name']) 
        return value['modules.js#name'];
    if (isGecko) {
        if (value.constructor) return value.constructor.name;
        return typeof value;
    }
    if (isSafari) return typeof(value);
    if (isOpera) {
        if (value.constructor) {
            try {
                return value.constructor.toString().match(/ (.*)(?=\()/)[1];
                /* perform regex magic on the string representation of the
                 * function to determine the name of the type */
            } catch (exception) {
                /* alright, so it doesn't always work */
                return "Unknown";
            }
        }
        return typeof value;
    }
    /*todo implement getTypeName for Explorer */
    throw "Implement me.";
};

/*** getTypeFullName
    returns the full type name of an instance in so far
    as its power permit.  Like `getTypeName` its
    return values are purely informational.  The usual
    recipie for a full type name is the `moduleUrl` of
    the module that the type was declared in with the exported
    name of the type as its anchor (after the ``#``).

     - `polymorphic`
*/
this.getTypeFullName = operator(1, 'getTypeFullName', getTypeName);

/*** as
    returns a value in a given type.  if the value
    is already the correct type, returns the
    original object.  if it isn't the correct type,
    converts it returning a shalow copy in the
    new type.

     - `polymorphic`
*/
this.as = operator(2, 'as', function (value, type) {
    if (isInstance(value, type)) return value;
    if (type === Number) return number(value);
    if (type === Array) return array(value);
    if (type === String) return string(value);
    return to(value, type);
});

/*** to
    converts an object to a given type, guaranteeing
    a shallow copy is returned.  defers to
    overloads functions in the value with the
    same full name as the given type, short name,
    or the `to` function respectively, if any
    of them are provided.  Otherwise, presumes
    that the type function is a copy constructor.

     - `polymorphic`
*/
this.to = operator(2, 'to', function (value, type) {
    if (isInstance(value, Function) && !isInstance(value, Base)) {
        return function () {
            return type(value.apply(this, arguments));
        };
    }
    var args = array(arguments);
    value = args.shift();
    type = args.pop();
    if (no(value))
        return type();
    if (isInstance(value, Base) && value[getTypeName(type)])
        return value[getTypeName(type)].apply(value, args);
    return type.apply(this, [value].concat(args));
});

/*** args

    accepts:
     - `value`: iterable of arguments
     - `functor`: function
     - `context`: optional (``this``) object

    returns the result of ``functor.apply(context, arguments)``,
    ascertaining that that the arguments are converted to an
    array.

    applies a given function, using the given
    arguments such that::

        args([1, 2, 3], sum) == sum(1, 2, 3)

    Usage::

        args(arguments, functor, [context])

    Also, composes functions such that that the first
    function passes its result into the second
    function as arguments.

*/
this.args = operator(2, 'args', function (values, functor, context) {
    if (isInstance(values, Function) && !isInstance(values, Base)) {
        return function () {
            return functor.apply(this, array(values.apply(this, arguments)));
        };
    }
    if (no(context)) context = this;
    return functor.apply(context, array(values));
});

/*** dir
    returns a list of attributes for a given object
    returns a `List` of all of a
    given instance's public member names.

    with no arguments, lists all of the
    public and module scope names in the
    current module.

     - `not-polymorphic`
*/
this.dir = foreignModuleBind(function (values) {
    if (arguments.length == 0)
        return sorted(objectKeys(this).concat(objectKeys(this.moduleScope)));
    if (no(values))
        return List();
    return List(objectKeys(values)).sorted();
});

/* vars
    attempts to implement vars in a fashion that worked
    and was useful all ended with melted CPU's.
    In the end, it was a waste of space.
    Ye be warned.
*/

/*** repr
    returns a string representation of the given object.
     - accepts any object
     - accepts an optional depth (defaults to `maxReprDepth`).
       `repr` will replace any object beneath this depth with
       an ellipsis (``...``).
     - accepts an optional memo `Set` of objects not to expand
       since they've presumably already been visited in the course
       composing a representation string.  `repr` will replace
       any object that's already been visited with a notation
       that there's a cycle, (``<cycle>``).

    `repr` uses these later arguments internally,
    and polymorphic overrides of the `repr` method on
    types constructed with `type` that compose the results
    of recursive `repr` calls are advised to use and
    pass these arguments back into this `repr` function.

    `repr` will fall back on `toString` in the unlikely
    event it can't come up with a reasonable representation
    of an object.  Sometimes this will result in an exception
    being throw.  `repr` sliently catches these exceptions
    and returns ``<unknown>`` with the exception or exception
    message.

     - `polymorphic`
*/
this.repr = function (value, depth, memo) {
    try {

        /* handle deep recursion */
        if (no(depth))
            depth = maxReprDepth;
        if (depth <= 0)
            return '...';
        depth--;

        /* handle primitives */
        if (no(value))
            return '' + value;
        if (isInstance(value, String))
            return enquote(value);
        if (isInstance(value, Number))
            return '' + value;
        if (isInstance(value, Boolean))
            return '' + value;
        if (isInstance(value, Date))
            return '' + value;

        /* handle cycles */
        if (no(memo))
            memo = Set();
        if (memo.has(value)) {
            return '<cycle>';
        } else {
            memo.insert(value);
        }

        /* handle compound objects */
        if (value.moduleScope)
            return '<module ' + value.moduleScope.moduleUrl + '>';
        if (isInstance(value, Base) || isInstance(value, type))
            return value.repr(depth, memo);
        /* dict would catch Functions without the Function case: */
        if (isInstance(value, Function)) {
            if (value['modules.js#fullName']) 
                return '<function ' + value['modules.js#fullName'] + '>';
            if (value.toString)
                return '<function>';
            return '<built-in-function>';
        }
        if (window.Node && isInstance(value, Node))
            return nodeRepr(value);
        if (isInstance(value, Array))
            return arrayRepr(value, depth, memo);
        if (isInstance(value, Object))
            return objectRepr(value, depth, memo);

        return value.toString();

    } catch (exception) {
        if (exception.message)
            return '<unknown ' + exception.message + '>';
        return '<unknown ' + exception + '>';
    }
};

/*** maxMemoDepth
    deters inifinite recursion in representations of complex objects.
    used by `repr`.  The default value is ``4``, but this can be
    changed by assigning to this name on the `base.js` module.
*/
this.maxReprDepth = 4;

/*** arrayRepr
    supports the same interface as `repr` but only
    operates on arrays.  `repr` uses this function internally.
    `arrayRepr` will perform better in situations where
    an object is guaranteed to be an `Array`.
*/
this.arrayRepr = function (values, depth, memo) {
    if (depth <= 0)
        return '[...]';
    return (
        '[' +
            arrayEach(values, function (value) {
                return repr(value, depth, memo);
            }).join(', ') +
        ']'
    );
};

/*** objectRepr
    supports the same interface as `repr` but only
    operates on associative array objects.  `repr` uses
    this function internally.
    `objectRepr` will perform better in situations where
    an object is guaranteed to be an `Object`.
*/
this.objectRepr = function (values, depth, memo) {
    if (depth <= 0)
        return '{...}';
    return (
        '{' +
            arrayEach(objectItems(values), function (pair) {
                return (
                    repr(pair[0], depth, memo) + ': ' +
                    repr(pair[1], depth, memo)
                );
            }).join(', ') +
        '}'
    );
};

/*** nodeRepr
    supports the same interface as `repr` but only
    operates on DOM nodes.  `repr` uses this function internally.
    `nodeRepr` will perform better in situations where
    an object is guaranteed to be a `Node`.
*/
this.nodeRepr = function (node) {
    if (node.nodeType == 1) 
        return '<' + lower(node.nodeName) + '>';
    if (node.nodeType == 3)
        return '<' + enquote(node.data) + '>';
    return '<?>';
};

/*** hash
    attempts to return a unique `String`
    for a given object of a native JavaScript or
    Chiron type.

    Defers to `toString` for nearly all JavaScript
    types.  This means that all objects are hashable
    but only make good dictionary or set indicies if
    they are not modified.
*/
/*
    various attempts to optimize hashing for native
    JavaScript objects have all failed.  For example,
    using `repr` resulted in infinite loops.
    One attempt involved dynamically adding a hash
    function to objects that returned a unique
    number.  The side effects were unsightly.
    Given that using objects or event arrays
    as hash keys is inadvisable in any case,
    I opted to stop trying to make it work
    well.
*/
this.hash = operator(1, 'hash', function (value) {
    try {
        return '' + value;
    } catch (exception) {
        /* some cyclic objects in Safari
         * throw an exception inside toString */
        return '';
    }
});


/**
    High Order Functions
    ====================
*/

/*** invoke
    calls/applies a given function, using the given
    arguments::

        ``inovke(a, b, ...z, functor)``

    For example::

        invoke(1, 2, 3, add) == add(1, 2, 3)

    The interface of this function may change in the
    future to look more like `args`.
*/
this.invoke = function () {
    /* cannot reuse arguments variable in Safari */
    var args = List(arguments);
    var functor = args.pop();
    return functor.apply(this, args.to(array));
};

/*** partial
    returns a function that supports partial application based
    on the number of arguments it accepts.  If additional
    arguments are applied to `partial` those are partially
    applied to the function.

    ``partial(function, [argument, [argument, [...]]]) -> function``
*/
this.partial = function () {
    var outerArgs = array(arguments);
    var functor = outerArgs.shift();
    if (!functor.partialLength)
        functor.partialLength = functor.length;
    var result = function () {
        var args = outerArgs.concat(array(arguments));
        if (args.length >= functor.partialLength) {
            return functor.apply(this, args);
        } else {
            return partial.apply(this, [functor].concat(args));
        }
    };
    result.partialLength = functor.partialLength - outerArgs.length;
    return result;
};

/**
    Logic
    =====
*/

/*** bool
    casts a value of a native or user defined
    type to a boolean `true` or `false`.
    `bool` defers to the `bool` method
    of any type that defines one.

     - `polymorphic`
*/
this.bool = function (value) {
    if (no(value)) return false;
    if (isInstance(value, Base)) {
        if (value.bool) return value.bool();
        if (value.number) return value.number() != 0;
    }
    return !!value;
};


/**
    Arithmetic
    ==========
*/

/*** number
    converts a value of a native or user defined
    type to a number.

     - `polymorphic`
*/
this.number = operator(0, 'number', function (value) {
    if (no(value)) return 0;
    /* this agrees with eq's behavior, so changes here
     * would impact its correctness. */
    return +value;
    /* unary plus exists in JavaScript only for
     * this toNumber conversion */
});

/*** add
    returns the sum of all of its arguments.

     - `stateless`
     - `polymorphic` on `added`
     - `currys` on less than 2 arguments
     - `commutative`
*/
this.add = operator(2, 'added', function (a, b) {
    if (arguments.length > 2) return sum(arguments);
    if (no(a)) return b;
    if (isInstance(a, Array)) return Array.prototype.concat(a, array(b));
    if (isInstance(a, Object)) return dict(a).added(b).object();
    if (isInstance(a, Number)) return a + number(b);
    if (isInstance(a, String)) return a + string(b);
    throw TypeError(
        "cannot add " + enquote(getTypeName(a)) +
        " with " + enquote(getTypeName(b)) + "."
    );
});

/*** sub
    subtracts the the later argument from the former.

     - `stateless`
     - `polymorphic` on `subed`
*/
this.sub = operator(2, 'subed', function (a, b) {
    return a - b;
});

/*** neg
    returns the arithmetic negation (negative) of
    a number.

     - `stateless`
     - `olymorphic` on `neged`
*/
this.neg = operator(1, 'neged', function (x) {return -x});

/*** mul
    returns the multiplicative product of all of its arguments.

     - `stateless`
     - `polymorphic` on `muled`
     - `commutative`
*/
this.mul = operator(2, 'muled', function (a, b) {
    if (arguments.length > 2) return product(arguments);
    if (no(a)) return b;
    if (no(b)) return a;
    if (isInstance(a, Iterable)) return repeat(a, b).sum();
    if (isInstance(a, Array)) return repeat(a, b).sum();
    if (isInstance(a, Number)) return a * number(b);
    /* stringMul is in boot.js */
    if (isInstance(a, String)) return stringMul(a, b);
    throw TypeError(
        "cannot multiply " + enquote(getTypeName(a)) +
        " with " + enquote(getTypeName(b)) + "."
    );
});

/*** div
    returns the quotient of the former over the latter argument.

     - `stateless`
     - `polymorphic` on `dived`
*/
this.div = operator(2, 'dived', function (a, b) {
    return a / b;
});

/*** mod
     - `stateless`
     - `polymorphic` on `moded`
*/
this.mod = operator(2, 'moded', function (a, b) {
    return a % b;
});

/*** pow
    returns the latter argument exponentiated on the former argument.

     - `stateless`
     - `polymorphic` on `powed`
     - `commutes` to `exp`
*/
this.pow = operator(2, 'powed', Math.pow);

/*** exp
    returns the former argument exponentiated on the latter argument.

     - `statless`
     - `polymorphic` on `exped`
     - `commutes` to `pow`
*/
this.exp = operator(2, 'exped', function (a, b) {
    return Math.pow(b, a);
});

/*** sum
    returns the arithmetic sum of the values in an `iterable`
    using `add`.

    accepts:
     - ``values`` an iterable of |addable| values.
     - ``basis`` an optional arithmetic identity.
       This defines the sum of empty ``values``, `undefined`
       by default.  Zero is an appropriate arithmetic identity
       for numbers, or an empty string or list for their
       respective types.

     - `stateless`
     - `polymorphic` on `added` via `add`
*/
this.sum = function (values, basis) {
    var result = basis;
    forEach(values, function (value) {
        result = add(result, value);
    });
    return result;
};

/*** product
    returns the multiplicative product of an iterable using `mul`.
    polymorphic by an override on `muled`.

    Accepts
     - ``values`` an iterable of multipliables.
     - ``basis`` an optional multiplicative identity.
       This defines the product of empty ``values``, ``undefined``
       by default.  One is an appropriate multiplicative
       identity for a product of numbers.
*/
this.product = function (values, basis) {
    var result = basis;
    forEach(values, function (value) {
        result = mul(result, value);
    });
    return result;
};


/**
    Comparison
    ==========
*/

/*** not
    returns the logical negation of a value.

     - `polymorphic` on `not` or via `bool`
*/
this.not = operator(1, 'not', function (x) {
    return !bool(x);
});

/*** and
    returns the logical intersection of two values.

     - `polymorphic` on `anded` or via `bool`
     - `currys` for fewer than 2 arguments
*/
this.and = operator(2, 'anded', function (a, b) {
    return bool(a) && bool(b);
});

/*** or
    returns the logical union of two values.

     - `polymorphic` on `ored` or via `bool`
     - `currys` for fewer than 2 arguments
*/
this.or = operator(2, 'ored', function (a, b) {
    return bool(a) || bool(b);
});

/*** eq
    equal.
    returns whether two objects are naturally equal.

     - identical objects (in memory) are equivalent.
     - values from the class of `Undefined` and `Null`
       are all equivalent to one another.
     - values from the class of `Function`, `String`,
       `Number`, and `Boolean` are all equivalent
       if they share the same value and type
       (JavaScript's strict equivalence).
     - `Array` objects are naturally equivalent if
       all of their values, the order of their values,
       and the quantities of values are equal.
     - `Object` instances are naturally equivalent
       if they have exactly the same values.
     - `Date` objects are naturally equivalent if
       their UTC strings are equal.

     - `polymorphic` on `eq`
*/
this.eq = operator(2, 'eq', function (a, b) {
    if (a === b) return true;
    if (no(a)) return no(b);
    if (
        isInstance(a, Function) ||
        isInstance(a, String) ||
        isInstance(a, Number) ||
        isInstance(a, Boolean)
    )
        return a === b;
    if (isInstance(a, Date))
        return (
            isInstance(b, Date) &&
            a.toUTCString() == b.toUTCString()
        );
    if (isInstance(a, Array))
        return List(a).eq(b);
    if (isInstance(a, Object))
        return Dict(a).eq(b);
    return false;
});

/*** ne
    not equal.
    returns whether two objects are not naturally
    equivalent.

     - `polymorphic` on `ne` or via `eq`
*/
this.ne = operator(2, 'ne', to(eq, not));

/*** lt
    less than.
    returns whether the former argument is naturally less than the
    latter argument.

     - `polymorphic`
     - `not-commutative`
*/
this.lt = operator(2, 'lt', function (a, b) {
    if (no(a) != no(b)) return no(a) > no(b);
    if (isInstance(a, Array)) return list(a).lt(b);
    if (isInstance(a, String) || isInstance(b, String)) return string(a) < string(b);
    return number(a) < number(b);
});

/*** gt
    greater than.
    returns whether the former argument is greater than the
    latter argument.

     - `polymorphic`
     - `not-commutative`
*/
this.gt = operator(2, 'gt', function (a, b) {
    return !(lt(a, b) || eq(a, b));
});

/*** le
    less than or equal.
    returns whether the former argument is less than or equal
    to the latter argument.

     - `polymorphic`
     - `not-commuative`
*/
this.le = operator(2, 'le', function (a, b) {
    return lt(a, b) || eq(a, b);
});

/*** ge
    greater than or equal.
    returns whether the former argument is greater than or
    equal to the latter argument.

     - `polymorphic`
     - `not-commuative`
*/
this.ge = operator(2, 'ge', to(lt, not));

/*** compare
    returns a number that is less than, equal to, or greater than
    0 reflecting the relationship between the former and
    latter argument.

     - `polymorphic` on `compare` or via `eq` or `lt`
     - `comparator`
*/
this.compare = operator(2, 'compare', function (a, b) {
    if (no(a) != no(b)) return no(b) - no(a);
    if (isInstance(a, Number) && isInstance(b, Number)) return a - b;
    return eq(a, b) ? 0 : lt(a, b) ? -1 : 1;
});

/*** desc
    a reverse `comparator`.

     - `polymorphic` on `compare` and `neg`
*/
this.desc = to(compare, neg);

/*** by
    returns a `comparator` that compares
    values based on the values resultant from
    a given `relation`.
    accepts a `relation` and an optional comparator.

    To sort a list of objects based on their
    "a" key::

        objects.sort(by(get("a")))

    To get those in descending order::

        objects.sort(by(get("a")), desc)

    `by` returns a comparison function that also tracks
    the arguments you used to construct it.  This permits
    `sort` and `sorted` to perform a Schwartzian transform
    which can increase the performance of the sort
    by a factor of 2.
*/
this.by = function (functor, compare) {
    if (no(compare))
        compare = module.compare;
    var comparator = function (a, b) {
        a = functor(a);
        b = functor(b);
        return compare(a, b);
    };
    comparator.by = functor;
    comparator.compare = compare;
    return comparator;
};

/*** naturally
    a `comparator` that sorts strings in "natural"
    as opposed to "lexical" order.  That is "1"
    appears before "10" in natural order.  ``naturally``
    uses `splitName` to break a string into words,
    then sorts textual words lexically, and numeric
    words numerically.
*/
this.naturally = by(function (value) {
    return splitName(value).each(function (word) {
        if (word == '' + Number(word))
            return Number(word);
        return word;
    });
});


/**
    Iteration
    =========
*/

/*** Iterable
    a mixin that adds convenience functions to types
    that implement `iter`.
*/

this.iterableMemberNames = [

    /**** forEach */ 'forEach',
    /**** forEachArgs */ 'forEachArgs',

    /**** eachIter */ 'eachIter',
    /**** each */ 'each',
    /**** eachArgsIter */ 'eachArgsIter',
    /**** eachArgs */ 'eachArgs',

    /**** whereIter */ 'whereIter',
    /**** where */ 'where',
    /**** whereArgsIter */ 'whereArgsIter',
    /**** whereArgs */ 'whereArgs',

    /**** args */ 'args',

    /**** zipIter */ 'zipIter',
    /**** zip */ 'zip',
    /**** transposeIter */ 'transposeIter',
    /**** transpose */ 'transpose',
    /**** enumerateIter */ 'enumerateIter',
    /**** enumerate */ 'enumerate',

    /**** reduce */ 'reduce',
    /**** cycle */ 'cycle',

    /**** flatten */ 'flatten',
    /**** compactIter */ 'compactIter',
    /**** compact */ 'compact',
    /**** withoutIter */ 'withoutIter',
    /**** without */ 'without',

    /**** group */ 'group',

    /**** sorted */ 'sorted',
    /**** reversed */ 'reversed',
    /**** reversedIter */ 'reversedIter',

    /**** added */ 'added',
    /**** chain */ 'chain',

    /**** min */ 'min',
    /**** max */ 'max',
    /**** sum */ 'sum',
    /**** product */ 'product',

    /**** all */ 'all',
    /**** any */ 'any',

    /**** join */ 'join',

    /**** object */ 'object'

];

this.Iterable = type(function () {
    var self = this;
    var alias = aliaser(self);
    var ed = eder(self);

    /* create methods dynamically */
    for (var i = 0; i < iterableMemberNames.length; i++) {
        var name = iterableMemberNames[i];
        self[name] = method(module[name]);
    }

    /**** reduced */
    self.reduced = ed('reduce');

    /**** flattened */
    self.flattened = alias('flatten');

    /**** added */
    self.added = alias('chain');

    /**** getLength
        returns the number of values in the iteration.

         - `stateful` (consumes the iteration)
    */
    self.getLength = function () {
        var length = 0;
        forEach(self, function () {
            length++;
        });
        return length;
    };

    /**** list
        creates a `List` of values from this iteration.

         - `stateful` (consumes the iteration)
         - `chainable`
    */
    self.list = method(List);

    /**** dict
        creates a `Dict` dictionary from the values
        or items (tuples) in this iteration.

         - `stateful` (consumes the iteration)
         - `chainable`
    */
    self.dict = method(Dict);

    /**** unique
        returns a `Set` (collection of unique values)
        constructed from the values in this iteration.

         - `stateful` (consumes the iteration)
         - `chainable`
    */
    self.unique = method(Set);

    /**** string
        returns a string of the joined values
        in the iteration.

         - `stateless`
    */
    self.string = method(join);

    /**** number
        returns the length of an iterable object.

         - `stateful` (consumes an iteration)
         - `chainable`
    */
    self.number = alias('getLength');

    /**** bool
        returns whether the iteraction contains any
        values.

         - `stateful` (consumes one iteration)
    */
    self.bool = function () {
        try {
            iter(self).next();
        } catch (exception) {
            if (isInstance(exception, StopIteration)) {
                return false;
            } else {
                throw exception;
            }
        }
        return true;
    };

    /**** array
        constructs an `Array` from the values in this
        iteration.

         - `stateful` (consumes one iteration)
    */
    self.array = method(iterArray);

    /**** object
        returns an `Object` that represents an associative 
        array of the items in this iteration, or items implied
        by the index of each value.

         - `stateless`
    */
    self.object = function () {
        var result = {};
        self.eachArgs(function (key, value) {
            result[key] = value;
        });
        return result;
    };

    /**** invoke
        retrieves indicies corresponding to the numbers
        in the range from a given iterable.

         - `stateful`
    */
    self.invoke = function (values) {
        var list = [];
        var iteration = iter(values);
        return self.each(function (i) {
            while (i >= list.length)
                list.push(iteration.next());
            return list[i];
        });
    };

});

/*** Iter
    an iteration.
    constructs an iterator instance given a successor
    function.  For example::

        var i = 0;
        Iter(function () {
            if (i++ < 10) {
                return i;
            } else 
                throw StopIteration();
            }
        });


    accepts:
     - a `next` funciton, one that returns the next
       value in an iterator or throws a `StopIteration`.
     - an optional ``hasNext`` function, one that
       returns ``true``, ``false``, or ``undefined``.
       By default, ``hasNext`` will always return
       ``undefined``.

*/
this.Iter = type([Iterable], function () {
    var self = this;
    var next;
    var hasNext;

    self.init = function (_next, _hasNext) {
        next = _next;
        hasNext = _hasNext;
    };

    /**** next
        returns the next element of the iteration.  Throws
        `StopIteration` if there are no more elements
        available.
    */
    self.next = function () {
        return next.call(self);
    };

    /**** nextCatch
        same as `next` except that it 
        returns `undefined` instead of throwing
        a `StopIteration` eexception.

        alternatly, accepts a default value
        to return instead of throwing `StopIteration`.
    */
    self.nextCatch = function (defaultNext) {
        try {
            return self.next();
        } catch (exception) {
            if (isInstance(exception, StopIteration))
                return defaultNext;
            throw exception;
        }
    };

    /**** hasNext
        returns whether the iteration has a next
        value.  This may be used to avoid using exceptions
        to probe for the end of an iteration.
        If the iteration cannot predict whether it
        has a successive value, returns ``undefined``.

        There are currently no implementations that use
        ``hasNext`` nor corresponding optimizations to 
        use ``hasNext`` implementations.
    */
    self.hasNext = function () {
        if (hasNext)
            return hasNext.call(self);
    };

    /**** iter
        since iterations are obviously iterable, returns
        itself.  If you need a copy of an iteration,
        look into using `tee`.
    */
    self.iter = function () {
        return self;
    };

});

/*** iter
    returns an `iterator` for any iterable type.  Defers to
    any user defined `iter` member function, if provided.
    `Iterable` types include `Object`, for which the iteration
    yields key value pairs, `Array`, `String`, for which
    the iteration yields the successive characters, and DOM
    elements or any type guaranteeing ``firstChild`` and
    ``nextSibling``.

     - `polymorphic`
*/
this.iter = operator(0, 'iter', function (values) {
    if (no(values)) return Iter(function () {throw stopIteration});
    if (isInstance(values, String)) return stringIter(values);
    if (isInstance(values, Array)) return arrayIter(values);
    if (window.Node ? isInstance(values, Node) : !no(values.firstChild))
        return elementIter(values);
    /* some arrays appear to be undetectable by type; consider ways to
     * remedy this in another way, please */
    if (!no(values.length)) return arrayIter(values);
    if (isInstance(values, Object)) return objectIter(values);
    throw Error("cannot iterate " + repr(values));
});

/*** objectIter
    constructs an iteration for native
    JavaScript `Object` instances.
*/
this.objectIter = function (items) {
    var keys = objectKeys(items);
    var i = 0;
    return Iter(function () {
        if (i < keys.length) {
            var key = keys[i++];
            return [key, items[key]];
        } else {
            throw stopIteration;
        }
    });
};

/*** arrayIter
    constructs an iteration for native
    JavaScript `Array` or array-like
    instances.  Works for any type that
    provides a ``length`` attribute
    and ``array[indexing]`` for successive
    numbers.
*/
this.arrayIter = function (values) {
    var i = 0;
    return Iter(function () {
        if (i < values.length) {
            return values[i++];
        } else {
            throw stopIteration;
        }
    });
};

/*** stringIter
    construts an iteration for the native
    JavaScript `String` type.

    `stringIter` is necessary because
    Internet Explorer JScript does not
    support string character indexing,
    necessitating the use of ``charAt``.
*/
this.stringIter = function (values) {
    var i = 0;
    return Iter(function () {
        if (i < values.length) {
            return values.charAt(i++);
        } else {
            throw stopIteration;
        }
    });
};

/*** nodeIter
    constructs an iteration of the child nodes
    of a DOM node.
*/
this.nodeIter = function (values) {
    var element = values.firstChild;
    return Iter(function () {
        var result = element;
        if (element) element = element.nextSibling;
        if (result) return result;
        else throw stopIteration;
    });
};

/*** elementIter
    returns an iteration of the tag children
    of a DOM element or element-like objects.
    Works for any type that provides
    ``firstChild`` and has children that
    provide ``nextSibling`` attributes.
*/
this.elementIter = function (values) {
    var element = values.firstChild;
    return Iter(function () {

        while (element && element.nodeType != 1)
            element = element.nextSibling;

        var result = element;
        if (element) element = element.nextSibling;
        if (result) return result;
        else throw stopIteration;
    });
};


/**
    Arithmetic Iterations
    =====================
*/

/*** range
    returns an ordinal `Range`.

    ``range(end)``
      the range of numbers [0, end)

    ``range(begin, end)``
      the range of numbers [begin, end)

    ``range(begin, end)``
      the range of numbers [begin, end) incrementing by step

*/
this.range = function (begin, end, step) {
    return Range(begin, end, step, ordinal);
};

/*** count
    returns a cardinal `Range`.

    ``count(end)``
        counts from [1, end]

    ``count(begin, end)``
        counts from [begin, end]

    ``count(begin, end, step)``
        counts from [begin, end] incrementing by step
*/

this.count = function (begin, end, step) {
    return Range(begin, end, step, cardinal);
};

/*** cardinal
    Denotes an interval that includes its bound.

    This variable may change name.
*/
this.cardinal = ']';

/*** ordinal
    Denotes an interval that excludes its bound.

    This variable may change name.
*/
this.ordinal = ')';

/*** Range
    a representation of an integral, bounded linear
    region.

    The domain of a range contains discrete integers,
    can be cardinal or ordinal, and can have a "step"
    between each pair of numbers like a "frequency".
    Cardinal ranges are inclusive of their terminal, "end",
    value and by default begin with one.
    Ordinal ranges are exclusive of their terminal, "end",
    value and by default begin with zero.

     - is `Iterable`

*/

this.Range = type([Iterable], function () {
    var self = this;
    var alias = aliaser(self);
    var begin, end, step, cardinality;

    this.init = function (_begin, _end, _step, _cardinality) {
        begin = _begin;
        end = _end;
        step = _step;
        cardinality = _cardinality;
        if (no(cardinality)) {
            cardinality = false;
        }
        if (no(begin)) {
            _cardinality = no(_cardinality) ? ordinal : _cardinality;
            begin = _cardinality === ordinal ? 0 : 1;
            end = Infinity;
            _step = 1;
        }
        if (no(end)) {
            end = begin;
            if (cardinality == cardinal) {
                begin = 1;
            } else {
                begin = 0;
            }
            if (no(step)) {
                step = 1;
            }
        }
        if (no(step)) {
            step = begin == end ? 0 : begin < end ? 1 : -1;
        }
    };

    /**** hasValue
        returns whether the range includes
        a given value.

        O(1): constant time; does not
        iterate over the range.  Guaranteed
        to return a value even for unbounded
        ranges like ``Range(-Infinity, Infinity)``.
    */
    self.hasValue = function (value) {
        if (step < 0)
            return self.reversed().hasValue(value);
        if (
            value < begin || 
            (
                cardinality == cardinal ? 
                value > end :
                value >= end
            )
        )
            return false;
        if (step == 0)
            return value == begin;
        if (begin % step != value % step)
            return false;
        return true;
    };

    /**** has
        returns whether range includes
        a given value.

         - aliases `hasValue`
    */
    self.has = alias('hasValue');

    /**** get
        returns the nth value in the range.
        if the index does not exist within
        the bounds of the range, throws
        a `KeyError`.
    */
    this.get = function (key) {
        var value = begin + key * step;
        if (!self.has(value))
            throw KeyError(key);
        return value;
    };

    /**** iter
        returns an iteration of the values
        in the range.
    */
    self.iter = function () {
        var n = begin;
        return Iter(function (iter) {
            if (
                end != null && (
                    step < 0 ? (
                        cardinality == cardinal ? n < end : n <= end
                    ) : (
                        cardinality == cardinal ? n > end : n >= end
                    )
                )
            ) {
                throw stopIteration;
            } else {
                var result = n;
                n += step;
                return step < 0 && ! cardinality == cardinal ? n : result;
            }
        });
    };

    /**** eq */
    self.eq = function (other) {
        if (no(other)) return false;
        if (isInstance(other, Range))
            return eq(self.getComponents(), other.getComponents());
        if (isInstance(other, Array) || isInstance(other, Iterable))
            return eq(self.array(), array(other));
        return false;
    };

    /**** reversed */
    self.reversed = function () {
        return Range(end, begin, -step, cardinality);
    };

    /**** repr
    */
    self.repr = function () {
        return (
            self.getTypeName() + '(' +
                repr(begin) + ', ' +
                repr(end) + ', ' +
                repr(step) + ', ' +
                repr(cardinality) +
            ')'
        );
    };

    /**** getComponents
        returns an array of the
        ``[begin, end, step, and cardinal]``
        internal variables.
    */
    self.getComponents = function () {
        /* normalize */
        if (cardinality == cardinal && !(step % 1))
            return [begin, end + 1, step, ordinal];
        return [begin, end, step, cardinality];
    };

});

/**

    Set
    ===

*/

/*** Set

    An unordered collection of unique values.

    The polymorphic member function corresponding to the
    `Set` constructor is `unique` since `Set` objects
    guarantee that their members are distinct.

    `Set` operations operate in constant time best case,
    and linear for degenerate cases.

    accepts:
     - an optional iterable of values to insert
     - an optional override for `eq` for determining
       whether itms with the same hash are the same
       object.
     - an optional override for `hash` for organizing
       potentially equivalent objects.

    If you mutate a List or Dict inside a set,
    it will be irrecoverable unless you retrieve a
    an object equivalent to the inserted value.

*/
this.Set = type([Iterable], function () {

    var data = {};
    var self = this;
    var ed = eder(self);
    var alias = aliaser(self);

    var eq;
    var hash;

    /*
        a utility function for Dict and Set that
        takes an value and constructs a hash key for
        an internal Object (string to value) mapping
        that guarantees that the key will not collide
        with an internal name like __proto__.
    */
    var encode = function (key) {
        return '~' + hash(key);
    };

    self.init = function (values, _eq, _hash) {
        if (no(eq = _eq))
            eq = module.eq;
        if (no(hash = _hash))
            hash = module.hash;
        if (!no(values)) {
            forEach(values, function (value) {
                self.insert(value);
            });
        }
        self.getSuper(Set).init.apply(self, arraySliced(arguments, 1));
    };

    /**** insert
        inserts a value in the `Set`. 
        Position is not relevant.  Replaces
        an existing value if the value has the same
        `hash` key and is `eq` to an existing
        value.  The `hash` function and `eq` function
        can be overridden in the `Set` constructor.

         - `stateful`
         - `chainable`
    */
    self.insert = function (value) {
        var hashKey = encode(value);
        if (!data[hashKey]) data[hashKey] = [];
        var i, bucket = data[hashKey];
        for (i = 0; i < bucket.length; i++) {
            if (eq(bucket[i], value)) {
                bucket[i] = value;
                return;
            }
        }
        /* assert(i == bucket.length) */
        bucket[i] = value;
        return self;
    };

    /**** retrieve
        retrieves a value from the `Set` that has
        the same `hash` key and is `eq` to a given
        value.  `eq` and `hash` can be overridden
        in the `Set` constructor.

         - `stateless`
    */
    self.retrieve = function (value) {
        var hashKey = encode(value);
        if (!(hashKey in data)) throw ValueError();
        var i, bucket = data[hashKey];
        for (i = 0; i < bucket.length; i++) {
            if (eq(bucket[i], value)) {
                return bucket[i];
            }
        }
        throw ValueError();
    };

    /**** remove
        removes a value from the `Set` if it has
        the same `hash` and is `eq` to the value.
        throws a `ValueError` if no matching value
        can be found.

         - `stateful`
         - `chainable`
    */
    self.remove = function (value) {
        var hashKey = encode(value);
        if (!(hashKey in data)) throw ValueError();
        var i, bucket = data[hashKey];
        for (i = 0; i < bucket.length; i++) {
            if (eq(bucket[i], value)) {
                /* move the value from the end over the deleted position */
                /* typical case: overwrites the target value
                 * and creates a redundant value */
                /* degenerate case: does nothing */
                bucket[i] = bucket[bucket.length - 1];
                /* remove the last value */
                /* typical case: removes the redundant value */
                /* degenerate case: removes the target value */
                bucket.pop();
                /* delete the bucket if it's empty */
                if (!bucket.length) {
                    delete data[hashKey];
                }
                return self;
            }
        }
        throw ValueError();
    };

    /**** discard
        discards a value from the `Set` if it has
        the same `hash` and is `eq` to the value.
        Unlike `remove`, does not throw a `ValueError`
        if no matching value can be found.

         - `stateful`
         - `chainable`
    */
    self.discard = function (value) {
        try {
            self.remove(value);
        } catch (exception) {
            if (isInstance(exception, ValueError)) {
            } else {
                throw exception;
            }
        }
        return self;
    };

    /**** clear
        removes all values in this set.

         - `stateful`
         - `chainable`
    */
    self.clear = function () {
        data = {};
        return self;
    };

    /**** has
        returns whether a set contains a given value.
        uses `eq` and `hash` to attempt to find
        the value in the set.  These functions
        can be overridden in the `Set` constructor.
    */
    self.has = function (value) {
        var hashKey = encode(value);
        if (!(hashKey in data))
            return false;
        var i, bucket = data[hashKey];
        for (i = 0; i < bucket.length; i++) {
            if (eq(bucket[i], value)) {
                return true;
            }
        }
        return false;
    };

    /**** find
        searches all of the values in set for one
        that is `eq` to a given value.  returns that
        value.  throws a `ValueError` if no value
        can be found.

         - accepts a value to find
         - accepts an optional override to the `eq` function

         - `stateless`
    */
    self.find = function (value, __eq) {
        var _eq = __eq;
        if (no(__eq)) _eq = eq;
        for (var hashKey in data) {
            var i, bucket = data[hashKey];
            for (i = 0; i < bucket.length; i++) {
                if (_eq(bucket[i], value)) {
                    return bucket[i];
                }
            }
        }
        throw ValueError("cannot find " + repr(value));
    };

    /**** iter */
    self.iter = function () {
        return objectIter(data).eachArgsIter(function (hashKey, bucket) {
            return arrayIter(bucket);
        }).sum(iter());
    };

    /**** eq */
    self.eq = function (other) {
        if (self == other) {
            return true;
        } else if (isInstance(other, Array) || isInstance(other, Iterable)) {
            return (
                self.getLength() == getLength(other) &&
                eachIter(other, function (value) {
                    return self.has(value);
                }).all()
            );
        } else {
            return false;
        }
    };

    /**** repr */
    self.repr = function (depth, memo) {
        var n = 0;
        return (
            self.getTypeName() + 
            '([' + (
                depth <= 0 ? 
                '...' :
                self.eachIter(function (value) {
                    return repr(value, depth, memo);
                }).join(', ')
            ) + '])'
        );
    };

    /**** union
        augments itself with any values that exist in another
        iterable.

         - `stateful`
         - `chainable`
    */
    self.union = function (values) {
        if (values === self) return self;
        forEach(values, function (value) {
            self.insert(value);
        });
        return self;
    };

    /**** intersect
         - `stateful`
         - `chainable`
    */
    self.intersect = function (values) {
        values = Set(values);
        self.forEach(function (value) {
            if (!values.has(value)) {
                self.remove(value);
            };
        });
        return self;
    };

    /**** difference
         - `stateful`
         - `chainable`
    */
    self.difference = function (values) {
        forEach(values, function (value) {
            self.discard(value);
        });
        return self;
    };

    /**** unioned
        returns all elements that are in itself and another iterable.

         - `stateless`
         - `chainable`
    */
    self.unioned = ed('union');

    /**** intersected
        returns all values that are in
        this set and another.

         - `stateless`
         - `chainable`
    */
    self.intersected = ed('intersect');

    /**** differenced
        returns the set of all values that are
        in this set but not another.

         - `stateless`
         - `chainable`
    */
    self.differenced = ed('difference');

    /**** symmetricDifferenced
        returns the set of all values that are exactly one
        set between itself and another.

         - `stateless`
         - `chainable`
    */
    self.symmetricDifferenced = function (values) {
        return self.getType()(self.unioned(values).whereIter(function (value) {
            return self.has(value) != has(values, value);
        }));
    };

    /**** isSuperSet
        returns whether this set contains all of the values
        in a given container.

         - `stateless`
    */
    self.isSuperSet = function (values) {
        values = as(values, Set);
        return values.eachIter(function (value) {
            return self.has(value);
        }).all();
    };

    /**** isSubSet
        returns whether a given container contains all of
        this set's values.

         - `stateless`
    */
    self.isSubSet = function (values) {
        values = as(values, Set);
        return self.eachIter(function (value) {
            return values.has(value);
        }).all();
    };

    /**** added
        alias of `unioned`

         - `stateless`
         - `chainable`
    */
    self.added = alias('unioned');

    /**** add
        alias of `union`

         - `stateful`
         - `chainable`
    */
    self.add = alias('union');

    /**** muled
        alias of `intersected`

         - `stateless`
         - `chainable`
    */
    self.muled = alias('intersected');

    /**** mul
        alias of `intersect`

         - `stateful`
         - `chainable`
    */
    self.mul = alias('intersect');

    /**** subed
        alias of `differenced`

         - `stateless`
         - `chainable`
    */
    self.subed = alias('differenced');

    /**** sub
        alias of `difference`

         - `stateful`
         - `chainable`
    */
    self.sub = alias('difference');

    /**** and
        alias of `intersect`

         - `stateful`
         - `chainable`
    */
    self.and = alias('intersect');

    /**** anded
        alias of `intersected`

         - `stateless`
         - `chainable`
    */
    self.anded = alias('intersected');

    /**** or
        alias of `union`

         - `stateful`
         - `chainable`
    */
    self.or = alias('union');

    /**** ored
        alias of `unioned`

         - `stateless`
         - `chainable`
    */
    self.ored = alias('unioned');

    /**** xor
        alias of `symmetricDifferenced`

         - `stateful`
         - `chainable`
    */
    self.xor = alias('symmetricDifferenced');

    /**** xored
        alias of `symmetricDifferenced`

         - `stateless`
         - `chainable`
    */
    self.xored = alias('symmetricDifferenced');

});

/*** unique
    constructs a `Set` from any given iterable.  This has the
    effect of returning an iterable object containing all of the
    unique elements from any given iteration.

    ``unique`` departs from the convention established by `list`,
    `List`, `dict`, and `Dict` in that you would expect the
    function to be called `set`, the camelCase variant of
    `Set`.  This transgression is necessary since the `set`
    function already exists as one of the "CRUD" operators in
    the company of `get`, `has`, `del`, and `put`.

     - `polymorphic`
*/
this.unique = operator(0, 'unique', Set);

/**

    Dictionary
    ==========

    Dictionaries, albeit instances of type `Dict`, are
    like associative arrays or hash tables.

*/

/*** Dict
    an associative array that maps objects to objects,
    a set of itmes that are key and value pairs, and a relation.

    `Dict` is an `Iterable` `Set`.

    Different than Python:

     - ``update``: `add`
     - ``has_key``: `hasKey`
     - ``iteritems``: `itemsIter`
     - ``iterkeys``: `keysIter`
     - ``itervalues``: `valuesIter`
     - ``fromkeys(S, v)``: ``dict(each(S.keys(), function (k) {return [k, v]}))``
     - ``setdefault``: use `set` and `get`
     - ``__del__`` -> `remove`
     - ``__contains__`` -> `has`

    Same as Python:

     - `get`
     - `clear`
     - `copy`
     - `items`
     - `keys`
     - `values`
     - `pop`

*/

this.Dict = type([Set], function () {

    var self = this;
    var alias = aliaser(self);
    var ed = eder(self);

    var parent;

    self.init = function (items, _parent, _eq, _hash) {

        if (no(_eq)) _eq = eq;
        if (no(_hash)) _hash = hash;
        self.getSuper(Dict).init(
            undefined,
            function (a, b) {
                return _eq(a[0], b[0]);
            },
            function (x) {
                return _hash(x[0]);
            }
        );

        if (items) {
            /* makes the iteration reusable */
            items = array(items);
            try {
                /* handle lists of tuples */
                eachArgs(items, function (key, value) {
                    if (arguments.length < 2)
                        throw Error(); /* for control flow */
                    self.set(key, value);
                });
            } catch (exception) {
                /* handle lists of items and
                 * assume positional indexing */
                self.clear();
                eachArgs(enumerate(items), function (key, value) {
                    self.set(key, value);
                });
            }
        }

        parent = _parent;

    };

    /**** keysIter
        returns an `Iter` of keys from the 
        key and value pairs (items) in the dictionary.
        Uses `itemsIter`.

         - `stateless`
    */
    self.keysIter = function () {
        return self.itemsIter().eachIter(get(0));
    };

    /**** keys
        returns a `Set` of keys from the 
        key and value pairs (items) in the dictionary.
        Uses `keysIter` and `itemsIter`.

         - `stateless`
    */
    self.keys = to(self.keysIter, Set);

    /**** valuesIter
        returns an `Iter` of values from the
        key and value pairs (items) in the dictinoary.
        Uses `itemsiter`.

         - `stateless`
    */
    self.valuesIter = function () {
        return self.itemsIter().eachIter(get(1));
    };

    /**** values
        returns a `List` of values from the
        key and value pairs (items) in the dictionary.
        Uses `valuesIter` and `itemsIter`.

         - `stateless`
    */
    self.values = to(self.valuesIter, List);

    /**** itemsIter
        returns an iteration, `Iter`, of the key and
        value pairs (items) in the dictionary.
        Items are represented as native JavaScript
        `Array` objects.
        Uses `iter`, which is defined for the
        `Set` base-type.

         - `stateless`
    */
    self.itemsIter = alias('iter');

    /**** items
        returns a `List` of the key and value
        pairs (items) in the dictionary.
        Items are represnted as native JavaScript
        `Array` objects.
        Uses `itemsIter`.

         - `stateless`
    */
    self.items = to(self.itemsIter, List);

    /**** get

        returns the value of an item in
        the dictionary that has a given
        key.  If there is item for the key,
        attempts to return a default value, 
        checking whether you've specified
        a default value to return as a second
        argument, or deferring to `getDefault`.
        If no acceptable default exists,
        throws a `KeyError`.

        accepts:
         - a key (any object)
         - an optional default value, which
           can be `undefined` or `null`
           if you wish to avoid throwing
           a `KeyError`.

         - `stateless`
    */
    self.get = function (key, value) {
        if (self.getSuper(Dict).has([key]))
            return self.retrieve([key])[1];
        if (arguments.length < 2)
            return self.getDefault(key);
        else
            return value;
    };

    /**** set 
        stores a key and corresponding value
        (an item) in the dictionary.  If
        an item already exists in the dictionary
        that has the same key, it is overwritten.

         - stateful
         - chainable
    */
    self.set = function (key, value) {
        return self.insert([key, value]);
    };

    /**** put
    */
    self.put = function (key, value) {
        if (self.has(key))
            throw KeyError("KeyError: " + repr(key) + " already exists");
        self.set(key, value);
    };

    /**** has
        returns whether a dictionary contains
        a given key.
    */
    self.has = function (key) {
        return self.getSuper(Dict).has([key]);
    };

    /**** cut
         - `stateful`
    */
    self.cut = function (key) {
        var result = self.get(key);
        self.del(key);
        return result;
    };

    /**** del
        deletes the key and value pair (item)
        in the dictionary
        that has a given key.

         - `stateful`
         - `chainable`
    */
    self.del = function (key) {
        return self.remove([key]);
    };

    /**** getDefault
        an overridable function that returns
        a value or throws a KeyError if you
        attempt to `get` an item for a key
        that the dictionary does not contain.

         - `stateless`, but overrides may
           be stateful.
    */
    self.getDefault = function (key) {
        if (no(parent)) {
            throw KeyError(key);
        } else { 
            return parent.get(key);
        }
    };

    /**** hasValue
        returns whether the dictionary contains
        an item with the given value.

         - `stateless`
    */
    self.hasValue = function (needle, findEq) {
        if (no(findEq)) findEq = eq;
        return self.valuesIter().whereIter(partial(findEq, needle)).any();
    };

    /**** hasKey
        alias of `has`

         - `stateless`
    */
    self.hasKey = alias('has');

    /**** update
         - `stateful`
         - `chainable`
    */
    self.update = alias('union');

    /**** updated
         - `stateless`
         - `chainable`
    */
    self.updated = alias('unioned');

    /**** complete
         - `stateful`
         - `chainable`
    */
    self.complete = function (other) {
        if (other === self) return self;
        eachArgs(other, function (key, value) {
            if (!self.has(key)) {
                self.set(key, value);
            }
        });
        return self;
    };

    /**** completed
         - `stateless`
         - `chainable`
    */
    self.completed = ed('complete');

    /**
        List
        ----
    */

    /**** find
         - `stateless`
    */
    self.find = function (value, findEq) {
        if (no(findEq)) findEq = eq;
        return self.getSuper(Dict).find([null, value], function (a, b) {
            return findEq(a[1], b[1]);
        })[0];
    };

    /**** findReverse
        since dictionary keys are not ordered, `findReverse` is not
        distinguishable from `find`.

         - `stateless`
    */
    self.findReversed = alias('find');

    /**
        Arithmetic
        ----------
    */

    /**** add
         - `stateful`
         - `chainable`
    */
    self.add = alias('update');

    /**** added
         - `stateless`
         - `chainable`
    */
    self.added = alias('updated');

    /**
        Logic
        -----
    */

    /**** eq
         - `stateless`
    */
    self.eq = function (other) {
        return self == other || (
            self.getLength() === getLength(other) &&
            self.keysIter().eachIter(function (key) {
                return has(other, key) && eq(self.get(key), get(other, key));
            }).all()
        );
    };

    /**
        Base
        ----
    */

    /**** repr
         - `stateless`
    */
    self.repr = function (depth, memo) {
        return self.getTypeName() + '(' + (
            depth <= 0 ?  '...' : 
            arrayRepr(array(self.items()), depth, memo)
        ) + ')';
    };

    /**
        Conversions
        -----------
    */

    /**** string
         - `stateless`
    */
    self.string = to(self.object, objectRepr);

    /**** hash
         - `stateless`
    */
    self.hash = function () {
        return self.itemsIter().eachArgs(function (key, value) {
            return hash(key) + hash(value);
        }).join(',');
    };

    /**** invoke
    */
    self.invoke = alias('get');

});

/*** dict
*/
this.dict = operator(0, 'dict', Dict);

/*** object
    Creates a new native JavaScript `Object`
    from any instance.

    Defers to any user defined `object` method
    of the given object.  Failing that, defers
    to `dict` to convert the given object to
    a `Dict` and then creates an `Object` from
    that dictionary's key value pairs.

     - `polymorphic`
*/
this.object = operator(0, 'object', function (value) {
    return dict(value).object();
});

/*** hasKey
     - `polymorphic`
*/
this.hasKey = operator(1, 'hasKey', function (items, key) {
    if (isInstance(items, Array)) {
        key = number(key);
        return key >= 0 && key < items.length;
    }
    if (isInstance(items, Object))
        return items[key] !== undefined;
});

/*** hasValue
     - `polymorphic`
*/
this.hasValue = operator(1, 'hasValue', function (items, value) {
    if (isInstance(items, Array))
        return arrayHas(items, value);
    if (isInstance(items, Object))
        return arrayHas(objectValues(items), value);
});

/*** update
     - `polymoprhic`
     - `stateful`
     - `chainable`
*/
this.update = operator(1, 'update', objectUpdate);

/*** updated
     - `polymorphic`
     - `stateless`
     - `chainable`
*/
this.updated = ed(update);

/*** complete
     - `polymoprhic`
     - `stateful`
     - `chainable`
*/
this.complete = operator(1, 'complete', objectComplete);

/*** completed
     - `polymorphic`
     - `stateless`
     - `chainable`
*/
this.completed = ed(complete);

/*** clear
    removes all key value pairs from list and dict-like objects
    including native Arrays, Objects, and types that override
    the `clear` function like `Dict` and `List`.

     - `polymorphic`
     - `stateful`
     - `chainable`
*/
this.clear = operator(1, 'clear', function (object) {
    if (isInstance(object, Array)) object.length = 0;
    else if (isInstance(object, Object)) 
        dir(object).forEach(function (name) {
            delete object[name];
        });
    return object;
});

/*** keys
     - `polymorphic`
     - `stateless`
*/
this.keys = operator(1, 'keys', function (items) {
    if (no(items)) return List();
    if (isInstance(items, Array)) return List(items).keys();
    if (isInstance(items, Object)) return Dict(items).keys();
});

/*** keysIter
     - `polymorphic`
     - `stateless`
*/
this.keysIter = operator(1, 'keysIter', function (items) {
    return iter(keys(items));
});

/*** values
     - `polymorphic`
     - `stateless`
*/
this.values = operator(1, 'values', function (items) {
    if (no(items)) return List();
    if (isInstance(items, Array)) return List(items);
    if (isInstance(items, Object)) return Dict(items).values();
});

/*** valuesIter
     - `polymorphic`
     - `stateless`
*/
this.valueIter = operator(1, 'valuesIter', function (items) {
    return iter(values(items));
});

/*** items
     - `polymorphic`
     - `stateless`
*/
this.items = operator(1, 'items', function (items) {
    if (no(items)) return List();
    if (isInstance(items, Array)) return List(items).items();
    if (isInstance(items, Object)) return Dict(items).items();
});

/*** itemsIter
     - `polymorphic`
     - `stateless`
*/
this.itemsIter = operator(1, 'itemsIter', function (value) {
    return iter(items(value));
});

/*** has
    returns whether a collection contains a value.
    Different collections may defer to `hasKey` or
    `hasValue` depending on what is most useful.
    `Dict` objects, for example, check keys from their
    contained items.

     - `polymorphic`
     - `stateless`
*/
this.has = operator(2, 'has', function (items, key) {
    if (isInstance(items, Array)) return arrayHas(items, key);
    if (isInstance(items, Object)) return key in items;
});

/*** get
     - `polymorphic`
     - `stateless`
*/
this.get = operator(2, 'get', function (items, key, value) {
    if (isInstance(items, String)) {
        if (!isInstance(key, Number))
            throw TypeError("TypeError: String keys must be Numbers.");
        if (!range(items.length).has(key))
            throw KeyError("KeyError: " + key);
        return items.charAt(key);
    }
    if (!isInstance(key, String))
        throw TypeError("TypeError: Object keys must be Strings");
    if (no(items[key])) {
        if (arguments.length == 3)
            return value;
        throw KeyError("KeyError: " + repr(key));
    } 
    return items[key];
});

/*** set
    sets a value for a given key in an associative mapping like a `Dict`, `Object`,
    `List`, `Array`, or any instance that implements `set`.

     - `polymorphic`
     - `stateful`
     - `chainable`
*/
this.set = operator(3, 'set', function (items, key, value) {
    items[key] = value;
    return items;
});

/*** put
     - `polymorphic` via `put` or `set`
     - `stateful`
     - `chainable`
*/
this.put = operator(3, 'put', arrayPut);

/*** del
    deletes an item from an object for a given key.
    If the object is ordered, an optional second argument can
    specify the exclusive upper bound to the range of keys
    to delete.
    If the object is one-dimensional, like an array, the
    keys are indicies (array offsets) and can be negative
    to indicate an offset from the array's length.  For
    example, ``-1`` is the last index of the array.
    The indicies must monotonically ascend; ``begin`` must be
    less than or equal to ``end``.

    accepts:
     - any object of items including an ``Object``, ``Array``,
       ``List``, or ``Dict``.
     - a ``key`` of any type as long as there is a corresponding
       instance in the object.

    throws a ``KeyError`` if any key does not exist.

    returns the original items.

     - `polymorphic`
     - `stateful`
     - `chainable`
*/
this.del = operator(2, 'del', function (values, begin, end) {
    if (isInstance(values, Array)) arrayDel(values, begin, end);
    else delete values[begin];
    return values;
});

/*** cut
     - `polymorphic` via `cut`, `get`, and `del`
     - `stateful`
*/
this.cut = operator(2, 'cut', function (items, key) {
    var result = get(items, key);
    del(items, key);
    return result;
});

/*** find
*/
/*todo account for the fact that arrayFind and objectFind are not
 * impolemented in terms of the "eq" function */
this.find = operator(2, 'find', function (items, value) {
    if (isInstance(items, Array)) return arrayFind(items, value);
    return objectFind(items, value);
});

/*** insert
*/
this.insert = operator(2, 'insert', function (items, value) {
    if (isInstance(items, Array)) items.push(value);
    throw TypeError("cannot insert on " + repr(getTypeName(items)));
});

/*** retrieve
*/
this.retrieve = function (items, value) {
    return get(items, find(items, value));
};

/*** remove
*/
this.remove = function (items, value) {
    return del(items, find(items, value));
};

/*** discard
*/
this.discard = function (items, value) {
    try {
        remove(items, value);
    } catch (exception) {
        if (isInstance(exception, ValueError)) {
        } else {
            throw exception;
        }
    }
    return items;
};

/*** member
    returns a function that will return a member of an
    object, calling an accessor function by name.
    accepts the name of the desired member.
    the returned function accepts the desired object.
    `member`, `by`, and `sorted` make an excellent team
    for sorting an array of objects by their respective
    values for a given member: ``sorted(lists, by(member('getLength')))``.
*/
this.member = function (name) {
    var args = array(arguments).slice(1);
    return function (object) {
        return object[name].apply(object, args);
    }
};


/**
    Lists
    =====
*/

/*** List 
    is `Iterable`

    Different than Python:

     - append: `push`
     - extend: `add`
     - count: `getLength`
     - index: `find`
     - insert: `put`
     - remove: `del`

    Same as Python:

     - `pop`
     - `sort`
     - `reverse`

*/
this.List = type([Iterable], function () {

    var self = this;
    var alias = aliaser(self);
    var ed = eder(self);
    var data = [];

    self.init = function (values) {
        if (!no(values)) {
            forEach(values, function (value) {
                data.push(value);
            });
        }
        this.getSuper(List).init();
    };

    /**** iter
         - `stateless`
    */
    self.iter = function () {
        return arrayIter(data);
    };

    /**** getLength
         - `stateless`
    */
    self.getLength = function () {
        return data.length;
    };

    /**** push
         - `stateful`
         - `chainable`
    */
    self.push = function (value) {
        data.push(value);
        return self;
    };

    /**** pop
         - `stateful`
    */
    self.pop = function () {
        if (data.length) {
            return data.pop();
        } else {
            throw ValueError("No elements on the stack.");
        }
    };

    /**** unshift
         - `stateful`
         - `chainable`
    */
    self.unshift = function (value) {
        data.unshift(value);
        return self;
    };

    /**** shift
         - `stateful`
    */
    self.shift = function () {
        if (data.length) {
            return data.shift();
        } else {
            throw ValueError("No elements in the queue.");
        }
    };

    /**** reverse
         - `stateful`
         - `chainable`
    */
    self.reverse = function () {
        data.reverse();
        return self;
    };

    /**** reversed
         - `stateless`
    */
    self.reversed = ed('reverse');

    /**** reversedIter
         - `stateless`
    */
    self.revsersedIter = function () {
        var i = data.length;
        return Iter(function () {
            if (i == 0) {
                throw stopIteration;
            } else {
                return data[--i];
            }
        });
    };

    /**** sort
         - `stateful`
         - `chainable`
    */
    self.sort = function (compare) {
        if (no(compare))
            compare = module.compare;
        if (compare.by) {
            /* schwartzian transform optimization */
            data = arrayEach(
                arrayEach(data, function (datum) {
                    return [compare.by(datum), datum];
                }).sort(function (a, b) {
                    return module.compare(a[0], b[0]);
                }),
                function (pair) {
                    return pair[1];
                }
            );
            
        } else {
            data.sort(compare);
        }
        return self;
    };

    /**** sorted
         - `stateless`
         - `chainable`
    */
    self.sorted = ed('sort');

    /**** slice
         - `stateful`
         - `chainable`
    */
    self.slice = function () {
        /* todo: resolve whether slice will behave like Python or Perl */
        data = data.slice.apply(data, arguments);
        return self;
    };

    /**** sliced
         - `stateless`
         - `chainable`
    */
    self.sliced = ed('slice');

    /**** splice
         - `stateful`
    */
    self.splice = function () {
        return List(data.splice.apply(data, arguments));
    };

    /**** spliced
         - `stateless`
         - `chainable`
    */
    self.spliced = ed('splice');

    /**** clear
         - `stateful`
         - `chainable`
    */
    self.clear = function () {
        data = [];
        return self;
    };

    /**** first
         - `stateless`
    */
    self.first = function (n) {
        if (!data.length) {
            throw KeyError(0);
        }
        if (no(n)) return data[0];
        return self.slice(0, n);
    };

    /**** last
         - `stateless`
    */
    self.last = function (n) {
        if (!data.length) {
            throw KeyError(-1);
        }
        if (no(n)) return data[data.length - 1];
        return self.slice(data.length - n, data.length);
    };

    /**** begins
        returns whether the first elements of
        a given list-like-object are equal, by way of `eq`,
        the respective elements in this list.

        In Python, this function is called ``startsWith``.
        This divergence from Python nomenclature is
        a matter of idealism.  Ideally the semantic group
        of `start`, `stop`, `pause`, `resume`,
        and `run` are all temporal verbs, whereas the
        semantic group `begins`, `ends`, `first`,
        `last`, and such all apply to the state of
        spatial segments or lists.

         - `stateless`
    */
    self.begins = function (other) {
        var iteration = iter(other);
        var result = zipIter(self, iteration).eachArgsIter(eq).all();
        return iteration.getLength() == 0 && result;
    };

    /**** ends
        returns whether the last elements of a given
        list-like-object are equal, by way of `eq`,
        the respective elements in this list.

        In Python, this function is called ``endsWith``.
        See ``startsWith`` for the rationale.

         - `stateless`
    */
    self.ends = function (other) {
        var iteration = iter(reversed(other));
        var result = zipIter(self.reversed(), iteration).eachArgsIter(eq).all();
        return iteration.getLength() == 0 && result;
    };

    /**** reduce
        reduce is an in place operation.
        see reduced for a stateless variant

         - `stateful`
         - `chainable`
    */
    self.reduce = function (recur) {
        while (data.length > 1) {
            data.unshift(
                recur(
                    data.shift(),
                    data.shift()
                )
            )
        }
        return self;
    };

    /**
        Dict
        ----
    */

    /**** keysIter
         - `stateless`
    */
    self.keysIter = function () {
        return range(data.length).iter();
    };

    /**** keys
         - `stateless`
    */
    self.keys = function () {
        return range(data.length).to(Set);
    };

    /**** valuesIter
         - `stateless`
    */
    self.valuesIter = alias('iter');

    /**** values
         - `stateless`
    */
    self.values = alias('copy');

    /**** itemsIter
         - `stateless`
    */
    self.itemsIter = function () {
        var key = 0;
        return eachIter(data, function (value) {
            return [key++, value];
        });
    };

    /**** items
         - `stateless`
    */
    self.items = function () {
        return self.itemsIter().to(List);
    };

    /**** get
         - `stateless`
    */
    self.get = function (key, value) {
        if (!isInstance(key, Number)) {
            throw KeyError(key);
        } else if (key < data.length) {
            return data[key];
        } else {
            if (arguments.length < 2) {
                throw KeyError(key);
            } else {
                return value;
            }
        }
    };

    /**** set
         - `stateful`
         - `chainable`
    */
    self.set = function (key, value) {
        data[key] = value;
        return self;
    };

    /**** put
        displaces the item at a given index, sending
        successive elements down the line.

         - `stateful`
         - `chainable`
    */
    self.put = function (key, value) {
        arrayPut(data, key, value);
        return self;
    };

    /**** cut
         - `stateful`
    */
    self.cut = function (key) {
        var result = self.get(key);
        self.del(key);
        return result;
    };

    /**** del

         - `stateful`
         - `chainable`
    */
    self.del = function (begin, end) {
        arrayDel(data, begin, end);
        return self;
    };

    /**** has
        returns whether the list contains
        a given value.

         - `stateless`
    */
    self.has = function (needle) {
        for (var key = 0; key < data.length; ++key) {
            var value = data[key];
            if (eq(needle, value)) {
                return true;
            }
        }
        return false;
    };

    /**** hasKey
        returns whether the list contains a value
        at a given index.

         - `stateless`
    */
    self.hasKey = function (key) {
        return isInstance(key, Number) && key < data.length;
    };

    /**** hasValue
        retunrs whether the list contains
        a given value.
        Uses `has`.

         - `stateless`
    */
    self.hasValue = alias('has');

    /**** find
        returns the first index of a given value
        in the list, or throws a `ValueError`
        if none can be found.

         - `stateless`
    */
    self.find = function (value, findEq) {
        if (no(findEq)) findEq = eq;
        for (var key = 0; key < data.length; ++key) {
            if (findEq(data[key], value)) {
                return key;
            }
        }
        throw ValueError(value);
    };

    /**** findReverse
        returns the last index of a given value
        in the list, or throws a `ValueError`
        if none can be found.

         - `stateless`
    */
    self.findReverse = function (value) {
        for (var key = data.length - 1; key >= 0; --key) {
            if (eq(data[key], value)) {
                return key;
            }
        }
        throw ValueError(value);
    };


    self.insert = alias('push');
    self.retrieve = method(retrieve);
    self.remove = method(remove);
    self.discard = method(discard);

    /**
        Arithmetic
        ----------
    */

    /**** add
         - `stateful`
         - `chainable`
    */
    self.add = function (values) {
        each(values, function (value) {
            data.push(value);
        });
        return self;
    };

    /**** added
         - `stateless`
         - `chainable`
    */
    self.added = ed('add');

    /**** eq
         - `stateless`
    */
    self.eq = function (other) {
        if (self == other) return true;
        if (isInstance(other, Array) || isInstance(other, Iterable))
            return (
                self.getLength() == getLength(other) &&
                self.zipIter(other).eachArgsIter(eq).all()
            );
        return false;
    };

    /**** lt
         - `stateless`
    */
    self.lt = function (other) {
        /*todo condense List.lt */
        if (self == other) return false;
        var a, as = self.iter();
        var b, bs = iter(other);
        while (true) {
            a = as.nextCatch();
            b = bs.nextCatch();
            if (no(a) && no(b)) return false;
            if (eq(a, b)) continue;
            if (lt(a, b)) return true;
            return false;
        }
        return false;
    };

    /**
        Logic
        ---------------
    */

    /**
        String
        ------
    */

    /**** join
         - `stateless`
    */
    self.join = function (delimiter) {
        if (no(delimiter)) delimiter = '';
        return data.join(delimiter);
    };


    /**
        Base
        ----
    */

    /**** repr
         - `stateless`
    */
    self.repr = function (depth, memo) {
        return self.getTypeName() + '(' + arrayRepr(data, depth, memo) + ')';
    };

    /**
        Conversions
        -----------
    */

    /**** array
         - `stateless`
    */
    self.array = function () {
        return copy(data); /* copies the internal array */
    };

    /**** hash
         - `stateless`
    */
    self.hash = function () {
        return eachIter(self, function (value) {
            return hash(value);
        }).join(',');
    };

});

/*** list
    constructs a List from any given iterable.

    polymorphic: define a `list` or `iter` member function.
*/
this.list = operator(0, 'list', List);

/*** array
    constructs a native JavaScript `Array` from
    any iterable.

     - `polymorphic` on `array` or `iter`
*/
this.array = operator(0, 'array', function (value) {
    if (isInstance(value, Array)) return copy(value);
    if (isInstance(value, Iterable)) return iterArray(value);
    return List(value).to(array);
});

/*** iterArray
    converts an `Iterable` to an `Array`.
*/
this.iterArray = function (value) {
    value = iter(value);
    var result = [];
    forEach(value, function (value) {
        result[result.length] = value;
    });
    return result;
};

/*** getLength
     - `polymorphic`
*/
this.getLength = operator(1, 'getLength', function (values) {
    if (no(values)) throw TypeError(values + " has no length.");
    if (isInstance(values, Base) && values.getLength) return values.getLength();
    if (values.length !== undefined) return values.length;
    if (isInstance(values, Object)) return objectKeys(values).length;
    throw TypeError("values have no length.");
});

/*** reversed
    returns a `List` of the values from an `Iteration`
    in reversed order.

     - `stateless`
*/
this.reversed = function (values) {
    return list(values).reversed();
};

/*** sorted
    returns a `List` of the values in a given `Iteration` in
    sorted order.  Accepts an optional override of `compare`.

     - `stateless`
*/
this.sorted = function (values, compare) {
    var object = list(values);
    return object.sort.apply(object, arraySliced(arguments, 1));
};

/*** sliced
     - `polymorphic`
     - `not-curry`
     - `stateless`
*/
this.sliced = operator(0, 'sliced', function (value, start, length) {
    if (no(value)) throw TypeError("Cannot slice " + value);
    if (isInstance(value, Array)) return arraySliced(value, start, length);
    if (isInstance(value, String)) return value.substring(start, length);
    throw TypeError("Cannot slice " + getTypeName(value));
});

/*todo splice */


/** 

    Operating on Iterables
    ======================

*/

/*** forEach
    calls a function for each value in a given iteration,
    a variant of `each` that does not return a `List`
    of results.

    Accepts
     - ``values``, an iterable object
     - ``functor``, a callable object that accepts an ``value``
     - ``context``, an optional context object to call the
       functor with instead of ``this``.

*/
/*
    Also accepts, but is not guaranteed to accept,
    a `collect` argument which is used to generalize
    the following consuming iterators whether they
    collect and return their results or not.
*/
this.forEach = function (values, functor, context, collect) {

    var results;

    if (no(functor))
        functor = pass;
    if (no(context))
        context = this;
    if (collect)
        results = List();

    var iteration = iter(values);

    try {
        while (true) {
            var result = functor.apply(context, [iteration.next()]);
            if (collect) {
                results.push(result);
            }
        }
    } catch (exception) {
        if (isInstance(exception, StopIteration)) {
        } else {
            throw exception;
        }
    }

    if (collect)
        return results;
    return values;
};

/*** forEachArgs
    iterates over an iteration of arrays, calling a given
    function with each array as variadic arguments.
    The iterands may be any iterable; they will be
    converted to arrays.

    accepts:
     - an `iterable` object that contains 
       iterable arguments objects.
     - a `Function`
     - an optional context object to call the
       function with.  By default, `forEach`
       passes its own context object.

    returns the original iterable.
*/
this.forEachArgs = function (values, functor, context) {
    if (no(functor))
        functor = pass;
    return forEach(values, function (value) {
        functor.apply(this, array(value));
    }, context);
};

/*** each
    returns a `List` of values produced from a
    given iteration and a relation on each value.

    accepts:
     - an `iterable` containing source values.
     - a `relation`, a function that accepts one
       value from some domain and returns a
       corresponding value in a range.
     - an optional context object to call the
       relation with.  By default, passes its
       own context object.

    `Dict` objects are relations by virtue of
    their callable behavior.  Dictionary lookup
    can be performed by calling the dictionary
    like a function, passing in a key.
*/
this.each = function (values, functor, context) {
    return forEach(values, functor, context, true);
};

/*** eachIter
    returns an iteration that produces values
    through a relation from a given iterable.
    This is a lazy form of `each`; it consumes
    only as many values from the source as are
    consumed by the user.  The source iteration
    may be indefinite, like the Fibonacci
    Sequence.
*/
this.eachIter = function (values, functor, context) {
    if (no(functor))
        functor = pass;
    if (no(context))
        context = this;
    var iteration = iter(values);
    return Iter(function () {
        return functor.call(context, iteration.next());
    });

};

/*** eachArgsIter
*/
this.eachArgsIter = function (values, functor, context) {
    if (no(functor))
        functor = pass;
    if (no(context))
        context = this;
    return eachIter(values, function (value) {
        return functor.apply(context, array(value));
    });

};

/*** eachArgs
*/
this.eachArgs = to(eachArgsIter, List);

/*** whereIter
*/
this.whereIter = function (values, functor, context) {
    var iteration = iter(values);
    return Iter(function () {
        while (true) {
            var value = iteration.next();
            if (functor.apply(context, [value])) {
                return value;
            }
        }
        /*
            the infinite while loop, above, will run until it
            either returns, or iteration.next() throws a
            StopIteration.  Or...it will run forever, but in
            any case, execution will never make it down to
            this return.
        */
        return;
    });
};

/*** where
*/
this.where = to(whereIter, List);

/*** whereArgsIter
*/
this.whereArgsIter = function (values, functor, context) {
    if (no(functor))
        functor = pass;
    if (no(context))
        context = this;
    return whereIter(values, function (value) {
        return functor.apply(context, array(value));
    });
};

/*** whereArgs
*/
this.whereArgs = to(whereArgsIter, List);

/*** mapIter
*/
this.mapIter = function (functor, values, context) {
    /* permute the arguments */
    return eachIter(values, functor, context);
};

/*** map

    accepts:
     - a relation `Function`
     - iterable values
     - an optional context object

    returns a `List` of respective values.

*/
this.map = function (functor, values, context) {
    return forEach(values, functor, context, true);
};

/*** forTimes

    accepts:
     - a number of times to call a function
     - a function or relation that may accept a number
       corresponding to the iteration number
       starting at zero.
     - an optional context object
    
    returns a range starting at 0 and
    as long as the number of times the
    function was called.

*/
this.forTimes = function (n, functor, context) {
    return forEach(range(n), functor, context);
};

/*** timesIter
    
    accepts:
     - a number of times to call a function
     - a relation that may accept the iteration
       number, starting at 0.
     - an optional context object

    returns an `Iter`

*/
this.timesIter = function (n, functor, context) {
    return eachIter(range(n), functor, context);
};

/*** times

    accepts:
     - a number of times to call a function
     - a relation that may accept the iteration
       number, starting at 0.
     - an optional context object

    returns a `List`

*/
this.times = to(timesIter, List);

/* transposes for iterations and tables */ 

/* all transposition functions really boil down to one function: */

/*** transposeIter
    returns an iteration of arrays, a row of elements for
    each column of a provided table.

    accepts an `iterable` of iterables.
*/
this.transposeIter = function (table) {
    if (arguments.length < 1) {
        throw TypeError("transposeIter requires a table argument");
    };
    var iterations = each(table, function (row) {
        return iter(row);
    });
    if (iterations.getLength() < 1) {
        return iter();
    }
    return Iter(function () {
        var exception;
        var result = each(iterations, function (iteration) {
            try {
                return iteration.next();
            } catch (innerException) {
                exception = innerException;
                throw exception;
            }
        });
        if (exception) {
            throw stopIteration;
        } else {
            return result.to(array);
        }
    });
}

/*** transpose
    returns the transpose of a rectangular iterable.  The rows of the 
    returned table are the columns of the provided table.

     - accepts an iterable of iterables.
     - returns a `List` of `Array` objects.

*/
this.transpose = to(transposeIter, List);

/*** zip
    returns the `transpose` of its arguments.
*/
this.zip = function () {
    return transpose.call(this, arguments);
};

/*** zipIter
    returns an iteration of the `transpose` of its arguments.
*/
this.zipIter = function () {
    return transposeIter.call(this, arguments);
};

/*** enumerateIter

    returns an iteration of enumerated values
    from a given iteration.

    accepts:
     - an `iterable` of values to enumerate
     - an optional number to start at: by
       default, 0.

    returns an iteration of array,
    ``[index, value]``, pairs.

*/
this.enumerateIter = function (values, n) {
    return zipIter(range(n), values);
};

/*** enumerate
    returns an iteration of duple arrays containing
    a sequential index and the respective value from
    a given iterable starting with zero, or ``n`` if
    provided.

    accepts:
     - ``values``
     - ``n`` an optional index for the first duple
       of the enumeration.  By default, this value
       is zero.
*/
this.enumerate = to(enumerateIter, List);

/*** reduce

    applies a function of two arguments cumulatively to the values of an
    iterable, from left to right, reducing the values to a single value.

    ``reduce`` has two argument forms.

     - ``reduce(values, recur)``
     - ``reduce(values, basis, recur)``

    For example, ``reduce([1, 2, 3], add)`` calculates ``((1 + 2) + 3)``.

    If one provides a ``basis``, that value primes the accumulator and
    serves as a default return value if the iteration is empty.

    For example, ``reduce([], 0, add)`` returns the arithmetic identity
    of zero, whereas ``reduce([], 1, mul)`` returns the multiplicative
    identity of one.  ``reduce([], [], add)`` returns an empty list,
    the 'list concatonation identity'.
    
    This function defies the conventional order of arguments
    for a reduction to facilitate orthogonality with the
    convention of having functor arguments come last and context
    objects come first.

*/
this.reduce = function (values, basis, recur) {
    /* copy the list, no matter its type */
    values = list(values);

    /* the two argument form omits a basis */
    if (no(recur)) {
        recur = basis;
        basis = undefined;
    }

    if (no(basis)) {
        basis = values.shift();
    }

    while (values.getLength() > 0) {
        basis = recur(basis, values.shift());
    }

    return basis;
};

/*** cycle
    returns an iteration that cycles through
    the values in a given iterable.

    accepts:
     - an iterable of values to 
       cycle over.
     - an optional number of times to cycle
       through the values: by default, `Infinity`.

    returns an iteration.
*/
this.cycle = function (values, count) {
    if (no(count)) count = Infinity;
    count = number(count);
    if (count == 0) return Iter(function () {
        throw stopIteration;
    });

    var buffer = [];
    var i = 0;

    var iteration = iter(values).eachIter(function (value) {
        /* first time around, fill the buffer on demand */
        buffer.push(value);
        return value;
    });

    return Iter(function () {
        try {
            return iteration.next();
        } catch (exception) {
            if (isInstance(exception, StopIteration)) {
                if (!no(count) && ++i > count)
                    throw stopIteration;
                iteration = iter(buffer);
                return iteration.next();
            } else {
                throw exception;
            }
        }

    });

};

/*** chain
    serially chains iterations.  the resultant
    iteration will consume and produce values from
    the first iteration, then consume and produce
    values from each following iteration in turn.
    adding and summing iterations has the same effect.

    if only one argument is passed in, it is presumed
    to be an iterable object containing the iterations
    you desire to chain.

    if more than one argument is passed in, the 
    arguments themselves are presumed to be a list
    of iterations to chain.
*/
this.chain = function () {

    var iterations;
    if (arguments.length == 1) {
        iterations = iter(arguments[0]);
    } else {
        iterations = iter(arguments);
    }

    var iteration = iter(iterations.next());
    return Iter(function () {
        while (true) {
            try {
                return iteration.next();
            } catch (exception) {
                if (isInstance(exception, StopIteration)) {
                    iteration = iter(iterations.next());
                } else {
                    throw exception;
                }
            }
        }
    });

};

/*** repeat
    returns an iteration that repeats an value a given number
    of times, or indefinitely.

    accepts
     - ``value``
     - ``length`` the optional number of times to repeat the ``value``

*/
this.repeat = function (value, length) {
    var i = 0;
    return Iter(function () {
        if (no(length) || i++ < length) {
            return value;
        } else {
            throw stopIteration;
        }
    });
};

/*** flatten
    returns a list of all of the non-list elements
    recursively contained by a given iterable object.
*/
this.flatten = function (values) {
    /*todo consider a non-recursive solution #69 */

    var results = List();
    forEach(values, function (value) {
        if (
            isInstance(value, Array) ||
            isInstance(value, Iterable)
        ) {
            forEach(flatten(value), function (value) {
                results.push(value);
            });
        } else {
            results.push(value);
        }
    });

    return results;
};

/*** compactIter
    returns an `Iter` of all of the values
    in a given `Iterable` that are not
    `null` or `undefined`.

    This function exists only to appease
    PrototypeJS afficionados.
*/
this.compactIter = function (values) {
    return whereIter(values, to(no, not));
};

/*** compact
    returns a `List` of all of the values
    in a given iterable that are not
    `null` or `undefined`.

    This function exists only to appease
    PrototypeJS afficionados.
*/
this.compact = to(compactIter, List);

/*** withoutIter
    returns an `Iter` of all of the values
    from a given iteration except those that
    are `eq` to a given value.

    accepts:
     - an `Iterable` of values
     - a value to exclude from the resultant
       iteration

*/
this.withoutIter = function (values, value) {
    return iter(values).whereIter(ne(value));
};

/*** without
    returns a `List` of all the values
    from a given iteration except those that
    are `eq` to a given value.

    accepts:
     - an `Iterable` of values
     - a value to exclude from the resultant
       `List`
*/
this.without = to(withoutIter, List);

/*** group
    groups the values in an `Iterable` based on
    the values a given relation returns.

    returns a `Dict` of `Set` objects for each
    class of values from the given iteration
    that returned the same value.  They keys
    of the dictionary are the common value.

    accepts:
     - an `Iterable` of values
     - a relation `Function`
     - an optional context object to call
       the relation with.

*/
this.group = function (values, functor, context) {
    if (no(context)) context = this;
    var groups = Dict();
    forEach(values, function (value) {
        var category = functor.call(context, value);
        if (!groups.has(category))
            groups.set(category, Set());
        groups.get(category).insert(value);
    });
    return groups;
};

/* a function that builds ``any`` and ``all`` */
var inferer = function (arity) {
    return function (values) {
        if (arguments.length > 1)
            values = iter(arguments);
        var iteration = iter(values);
        try {
            while (true) {
                var value = iteration.next();
                if (bool(value) != arity) {
                    return !arity;
                }
            }
        } catch (exception) {
            if (isInstance(exception, StopIteration)) {
            } else {
                throw exception;
            }
        }
        return arity;
    };
};

/*** all
    returns whether all of the values
    in an `Iterable` are true.  Consumes
    only as many values from the
    iteration as necessary.  This means
    that `all` short-circuits on t