To create sets of unary predicates for different purposes.

§1. Want to create a new unary predicate? First you'll need a family for it to belong to. A up_family object is simply a receiver for the method calls providing the predicate's implementation. In effect, a family is a collection of UPs which share an implementation.

typedef struct up_family {
    struct method_set *methods;
    CLASS_DEFINITION
} up_family;

up_family *UnaryPredicateFamilies::new(void) {
    up_family *f = CREATE(up_family);
    f->methods = Methods::new_set();
    return f;
}

§2. STOCK_UPF_MTID is for stocking up on unaries, and happens very early in Inform's run.

enum STOCK_UPF_MTID
VOID_METHOD_TYPE(STOCK_UPF_MTID, up_family *f, int n)

void UnaryPredicateFamilies::stock(int n) {
    up_family *f;
    LOOP_OVER(f, up_family)
        VOID_METHOD_CALL(f, STOCK_UPF_MTID, n);
}

§3. This method performs a type-check to see whether the value supplied as the term of the predicate is acceptable. For example, even(t) should reject t if it is a text, because even is meaningful only for numbers.

enum TYPECHECK_UPF_MTID
typedef struct variable_type_assignment {
    struct kind *assigned_kinds[26];  one for each of the 26 variables
} variable_type_assignment;

INT_METHOD_TYPE(TYPECHECK_UPF_MTID, up_family *f, unary_predicate *up,
    pcalc_prop *prop, variable_type_assignment *vta, tc_problem_kit *tck)

int UnaryPredicateFamilies::typecheck(unary_predicate *up,
    pcalc_prop *prop, variable_type_assignment *vta, tc_problem_kit *tck) {
    int rv = DECLINE_TO_MATCH;
    INT_METHOD_CALL(rv, up->family, TYPECHECK_UPF_MTID, up, prop, vta, tck);
    return rv;
}

§4. A unary predicate is "testable" if its truth can be determined at compile time. (We assume everything can be tested at run time.) For example, kind=number(t) can generally be tested at compile time, but even(t) cannot.

enum TESTABLE_UPF_MTID
INT_METHOD_TYPE(TESTABLE_UPF_MTID, up_family *f, unary_predicate *up)

int UnaryPredicateFamilies::testable(unary_predicate *up) {
    int rv = FALSE;
    INT_METHOD_CALL(rv, up->family, TESTABLE_UPF_MTID, up);
    return rv;
}

§5. And for a testable UP, the following should perform that test. It will never be called for non-testable ones.

enum TEST_UPF_MTID
INT_METHOD_TYPE(TEST_UPF_MTID, up_family *f, unary_predicate *up,
    TERM_DOMAIN_CALCULUS_TYPE *about)

int UnaryPredicateFamilies::test(unary_predicate *up, TERM_DOMAIN_CALCULUS_TYPE *about) {
    int rv = FALSE;
    INT_METHOD_CALL(rv, up->family, TEST_UPF_MTID, up, about);
    return rv;
}

§6. Assertion is used in Inform when constructing the model world. The calculus module doesn't really get involved in this, and provides this method only for Inform's benefit.

enum ASSERT_UPF_MTID
VOID_METHOD_TYPE(ASSERT_UPF_MTID, up_family *f, unary_predicate *up,
    int now_negated, pcalc_prop *pl)

void UnaryPredicateFamilies::assert(unary_predicate *up,
    int now_negated, pcalc_prop *pl) {
    VOID_METHOD_CALL(up->family, ASSERT_UPF_MTID, up, now_negated, pl);
}

§7. Schemas are used in compilation: see Compilation Schemas for more. Again, the calculus module doesn't really get involved in this.

enum SCHEMA_UPF_MTID
VOID_METHOD_TYPE(SCHEMA_UPF_MTID, up_family *f, int task, unary_predicate *up,
    annotated_i6_schema *asch, kind *K)

void UnaryPredicateFamilies::get_schema(int task, unary_predicate *up,
    annotated_i6_schema *asch, kind *K) {
    VOID_METHOD_CALL(up->family, SCHEMA_UPF_MTID, task, up, asch, K);
}

§8. If the usage of this UP implies the kind of its term, here's where we say so. The obvious example is kind=K(t), which necessarily means t has kind K. But one could also imagine UPs which are appropriate only for, say, real numbers.

enum INFER_KIND_UPF_MTID
VOID_METHOD_TYPE(INFER_KIND_UPF_MTID, up_family *f, unary_predicate *up, kind **K)

kind *UnaryPredicateFamilies::infer_kind(unary_predicate *up) {
    kind *K = NULL;
    VOID_METHOD_CALL(up->family, INFER_KIND_UPF_MTID, up, &K);
    return K;
}

§9. Logging should be brief: something like kind=number is plenty.

enum LOG_UPF_MTID
VOID_METHOD_TYPE(LOG_UPF_MTID, up_family *f, text_stream *OUT,
    unary_predicate *up)

void UnaryPredicateFamilies::log(OUTPUT_STREAM, unary_predicate *up) {
    VOID_METHOD_CALL(up->family, LOG_UPF_MTID, OUT, up);
}