# Lesson XII
The brush may be steady, yet a fine stroke asks for ink that will not run.
## Try
```prolog
% ?- E = kernel, infer(E, [dup, add], Scheme).
% Scheme = scheme([requires(numeric, A)], effect([A|S], [A|S])).
% ?- E = kernel, infer(E, [dup, eq], Scheme).
% Scheme = scheme([requires(equatable, B)], effect([B|T], [bool|T])).
% ?- E = kernel, infer(E, [push(bool(true)), dup, add], Scheme).
% Scheme = scheme([requires(numeric, bool)], effect(S, [bool|S])).
```
## Lesson
```prolog
word(kernel, add, [A::T, B::T|S] -- [C::T|S], [requires(numeric, T)], C is B + A).
word(kernel, sub, [A::T, B::T|S] -- [C::T|S], [requires(numeric, T)], C is B - A).
word(kernel, mul, [A::T, B::T|S] -- [C::T|S], [requires(numeric, T)], C is B * A).
word(kernel, eq, [A::T, B::T|S] -- [Bool::bool|S], [requires(equatable, T)], (A == B -> Bool = true ; Bool = false)).
word(kernel, lt, [A::T, B::T|S] -- [Bool::bool|S], [requires(numeric, T)], (B < A -> Bool = true ; Bool = false)).
word(kernel, gt, [A::T, B::T|S] -- [Bool::bool|S], [requires(numeric, T)], (B > A -> Bool = true ; Bool = false)).
find(Env0, Word, InOut, Constraints, Goal) :-
nonvar(Env0),
word(Env0, Word, StoredInOut, StoredConstraints, StoredGoal),
copy_term(word(Word, StoredInOut, StoredConstraints, StoredGoal), word(Word, InOut, Constraints, Goal)).
% Fixed words project through primitive rows.
apply(Env, Word, Stack0, Stack) :-
find(Env, Word, InPattern -- OutPattern, Constraints, Goal),
bind(InPattern, Stack0),
holds(Constraints),
call(Goal),
build(OutPattern, Stack).
infer(Env, Words, scheme(Constraints, effect(In, Out))) :-
infer(Env, Words, effect(In, Out), Constraints, []).
infer(_, [], effect(Stack, Stack), Constraints, Constraints).
infer(Env, [Word|Words], effect(Stack0, Stack), Constraints0, Constraints) :-
infer1(Env, Word, effect(Stack0, Stack1), Constraints0, Constraints1),
infer(Env, Words, effect(Stack1, Stack), Constraints1, Constraints).
infer1(Env, push(Value), effect(Stack, [Type|Stack]), Constraints, Constraints) :-
!,
lit(Env, Value, Type).
infer1(_Env, call, effect([quote(Scheme)|Stack0], Stack), Constraints0, Constraints) :-
!,
copy_term(Scheme, scheme(NewConstraints, effect(Stack0, Stack))),
append(NewConstraints, Constraints, Constraints0).
infer1(Env, Word, effect(Stack0, Stack), Constraints0, Constraints) :-
find(Env, Word, InPattern -- OutPattern, NewConstraints, _Goal),
types(InPattern, Stack0),
types(OutPattern, Stack),
append(NewConstraints, Constraints, Constraints0).
supports(int, numeric).
supports(int, equatable).
supports(bool, equatable).
holds([]).
holds([requires(Name, Type)|Constraints]) :-
nonvar(Type),
supports(Type, Name),
holds(Constraints).
```