# Lesson XIII The brush meets the ink. Holding opens the way; unknown remains open; running closes the stroke. ## Try ```prolog % ?- E = kernel, infer(E, [dup, add], Scheme). % Scheme = scheme([requires(numeric, A)], effect([A|S], [A|S])). % ?- E = kernel, infer(E, [push(int(1)), dup, add], Scheme). % Scheme = scheme([], effect(S, [int|S])). % ?- E = kernel, infer(E, [push(bool(true)), dup, add], Scheme). % ERROR: forth_error(constraint, unsatisfied, requires(numeric, bool)). ``` ## Lesson ```prolog apply(Env, Word, Stack0, Stack) :- find(Env, Word, InPattern -- OutPattern, Constraints, Goal), bind(InPattern, Stack0), solve(Constraints, []), call(Goal), build(OutPattern, Stack). infer(Env, Words, scheme(Constraints, effect(In, Out))) :- infer(Env, Words, effect(In, Out), RawConstraints, []), solve(RawConstraints, Constraints). % `solve/2` performs one local reduction at a time. % % * `requires(numeric, A)` stays open when `A` is a variable. % * `requires(numeric, int)` disappears because `int` is numeric. % * `requires(numeric, bool)` throws because `bool` has no numeric % support. solve([], []). solve([Constraint|Constraints0], Constraints) :- reduce1(Constraint, More), solve(Constraints0, Rest), append(More, Rest, Constraints). reduce1(requires(Name, Type), [requires(Name, Type)]) :- var(Type), supports(_, Name), !. reduce1(requires(Name, Type), []) :- supports(Type, Name), !. reduce1(Constraint, _) :- throw(error(forth_error(constraint, unsatisfied, Constraint), _)). ```