Authoritative source: Laws and deriving

Laws and deriving

Laws record algebraic propositions. Deriving builds ordinary instances from checked derivation logic. Neither feature creates proof or optimization trust by assertion alone.

Declaring laws

law associativity(x:a, y:a, z:a) =
    combine(combine(x,y),z) === combine(x,combine(y,z));

law transitivity(x:a, y:a, z:a) =
    (x <= y) === True ==>
    (y <= z) === True ==>
    (x <= z) === True;

=== forms propositional equality. ==> is right-associative implication. A law must type-check and is inherited with its structure.

What declaration does not mean

A law declaration does not automatically:

Law status may be declared, tested, proven, trusted by build policy, or compiler-validated according to the semantic design. The default surface law is a well-typed, testable proposition.

Derive blocks

algebra Show(a:Type) = {
    function show(item:a) : String;
    derive {
        function show(item:a) : String =
            structuralShow(reflect(item), item)
    }
};

Reflection used by derivation is compile-time, typed, and target-neutral. TypeRep(a) identifies the checked type, while DataShape/DataCode preserve its constructor and flat field telescopes without exposing native offsets or storage. A data declaration can request the result:

type Color = Red + Green + Blue deriving Eq, Show;

Each algebra must provide valid derivation logic. The generated instance goes through ordinary member, evidence, coherence, and law checks.

For parameterized data, field requirements are inferred:

type Box(a:Type) = Box * item:a;
instance Eq(Box(a)) = derive;

The generated equality provider requires Eq(a). Closed field requirements are resolved while deriving; missing or ambiguous closed evidence is an error. An explicit requires clause must cover every requirement the recipe discovers.

Recipes may also request supporting evidence or reject generation directly:

function checkedShow(item:a) : String =
    let available = requireEvidence(Show(String)) in
    structuralShow(reflect(item), item)

requireEvidence is handled during derivation and never becomes a runtime call. rejectDerivation(error) stops generation with a structured static diagnostic. These are compile-time capabilities, not general runtime effects.

Computing data from typed codes

DataCode can also be transformed by ordinary pure Tulam helper functions:

type Source(a:Type) = None + Some * item:a;

function schema(code:DataCode(Unit, Z)) : DataCode(Unit, Z) =
    renameConstructor(
        renameConstructor(renameDataType(code, "Generated"),
            "None", "Absent"),
        "Some", "Present");

type Generated(a:Type) = schema(dataCode(reflect(Source(a))));

The computed body must return a code whose name and parameter arity match the declaration. The compiler materializes normal constructors, then runs the same positivity, coverage, type, evidence, and native gates as handwritten data. Opaque type shape and target layout cannot be inspected this way.

Classes choose semantics explicitly

implements Eq(Key) means matching class methods define class-owned equality. It does not silently switch to structural equality. Structural class behavior uses a separate instance Eq(Point) = derive and is allowed only for a sealed leaf class, where the field shape is closed.

Laws versus tests

A test observes selected values; a law states a proposition over all values in its binders. Property testing may sample a law when generator evidence exists, but successful samples are not a proof. Both remain useful and honestly named.

Common mistakes

Do not treat a declared law as Refl, an optimizer permission, or proof that floating arithmetic obeys exact field identities. Do not use runtime reflection where a compile-time DataCode is required, inspect provider layout from a derive recipe, or assume class implements derives missing behavior. A derived instance still has to satisfy ordinary typing, coherence, and law policy.

Recap

Laws preserve named propositions; deriving supplies checked implementation logic. Proof, testing, trust, and optimization eligibility remain explicit separate statuses.

Normative details: Language Reference §9.6, §10, and §11.7-11.9.