Lurch Deductive Engine

source

binding-environment.js


import { MathConcept } from './math-concept.js'
import { Environment } from './environment.js'
import BindingInterface from './binding-interface.js'

/**
 * A binding in general is defined in the documentation for the
 * {@link BindingInterface BindingInterface}.  Refer there for the general
 * principles.  This class uses that interface to implement bindings whose
 * bodies are {@link Environment Environments}.
 */
export class BindingEnvironment extends Environment {
    
    static className = MathConcept.addSubclass(
        'BindingEnvironment', BindingEnvironment )

    /**
     * Construct a new BindingEnvironment instance from the given array of bound
     * variables (one or more {@link Symbol Symbols}) and body (required
     * {@link Environment}).  Recall from the documentation of the
     * {@link BindingInterface BindingInterface} that bindings do not contain an
     * operator, but {@link BindingEnvironment BindingEnvironments} typically do
     * not want one, so there is not always a need to wrap the resulting object
     * in a larger {@link LogicConcept LogicConcept}.
     * 
     * For example, when encoding something like a subproof that treats $x$ as
     * an arbitrary variable and eventually proves some expression $P$
     * containing $x$, we might use a
     * {@link BindingEnvironment BindingEnvironment} like the following to
     * represent it.
     * 
     * ```js
     * new BindingEnvironment(
     *     new LurchSymbol( 'x' ),
     *     new Environment(
     *         step1, // some Expression
     *         step2, // some Expression
     *         // and so on, eventually reaching the expression:
     *         P
     *     )
     * )
     * ```
     * 
     * Note that while it is possible later to remove children from a
     * BindingEnvironment so that it does not have the required structure of
     * symbols-then-body, this is almost certain to result in the members of
     * this class malfunctioning or throwing errors.  Clients should not remove
     * the necessary children of a BindingEnvironment; that is not supported.
     * 
     * Although it is unnecessarily to repeat the same variable twice on the
     * list of bound variables, we do not explicitly forbid it.
     * 
     * @param  {...LogicConcept} args - the list of one or more
     *   {@link Symbol Symbols} that this environment binds, followed by its
     *   body, which must be of type {@link Environment Environment}.
     * @throws This constructor throws an error if any argument is not a
     *   {@link LogicConcept LogicConcept}, or if any argument but the last is
     *   not a {@link Symbol Symbols}, or the last argument is not an
     *   {@link Environment Environment}, or if the list of bound symbols is
     *   empty.
     */
    constructor ( ...args ) {
        if ( args.length < 2 )
            throw new Error( 'A BindingEnvironment requires at least 2 arguments' )
        const body = args.pop()
        if ( !BindingInterface.allAreSymbols( args ) )
            throw new Error( 'Every argument given to a BindingEnvironment '
                           + 'constructor (except the last) must be a Symbol' )
        if ( !( body instanceof Environment ) )
            throw new Error( 'The body in a BindingEnvironment constructor '
                           + 'must be an Environment' )
        super( ...args, body )
    }

}

// Install the interface into the class defined above.
BindingInterface.addTo( BindingEnvironment.prototype )