The checker's real product is an answer a person can read - a type, or an error. Today you wrap inference in a single report function that returns the inferred type as text on success, or the located error message on failure.
Build a report function that returns the inferred type printed, or the located error message.
Everything the checker computes has been reachable only through Infer returning a
Type or an error. The finished product needs one honest entry point that a
person - or a demo program - can call and read: give it a program, get back either
the type it inferred or the error explaining why it has none. Report is that
function. On success it runs the type through Show, so a polymorphic result reads
back as a -> a with tidy variable names; on failure it returns the error’s message,
which already carries a source position when the program was built with At.
This is a small function but an important seam. It is the difference between a
library of internal pieces and a tool with a clear surface: Report is what the
capstone calls, and what the finalize step will wrap in a runnable demo that infers a
built-in program and prints its type or its located error. Keeping the two outcomes -
a printed type and a located message - behind one call means the rest of the world
never has to know how inference is plumbed inside. The next lesson checks that all
three kinds of error flow through this report cleanly.
// one entry point that turns a program into a line of text.func Report(env Env, e Expr) string {t, err := Infer(env, e)if err != nil { return err.Error() } // already located, if wrapped in Atreturn Show(t) // the principal type, variables as a, b, c}