# Lesson IV
The eye and hand now bow to one form. When seeing and doing serve one form, the stroke becomes honest.
## Try
```prolog
% ?- word(dup, In -- Out, Goal).
% In = [_A|_S],
% Out = [_A, _A|_S],
% Goal = true.
% ?- apply(over, [a, b], Stack).
% Stack = [b, a, b].
% ?- infer([dup, swap], In, Out).
% In = [_A|_S],
% Out = [_A, _A|_S].%
```
## Learn
```prolog
% A primitive equation is not yet a type scheme. It is just the shared
% one-word fact that both projections need:
%
% * the input stack pattern;
% * the output stack pattern;
% * the runtime goal to run between them.
%
% The `--/2` operator is ordinary Prolog syntax. It gives the visual
% shape of a stack transition without introducing a separate parser.
%
% The four shufflers have `true` as their runtime goal because they
% only move stack cells. The whole behavior is already captured by
% unifying the input and output patterns.
:- op(700, xfx, --).
word(dup, [A|S] -- [A, A|S], true).
word(drop, [_|S] -- S, true).
word(swap, [A, B|S] -- [B, A|S], true).
word(over, [A, B|S] -- [B, A, B|S], true).
% Runtime projects a concrete stack transformation from the primitive
% equation. It chooses a row, matches the real stack against the row's
% input pattern, runs the row's goal, then returns the row's output
% pattern.
%
% For this first primitive stage, matching is just unification. That is
% enough because stack shufflers do not inspect payloads or validate
% types.
apply(Word, Stack0, Stack) :-
word(Word, InPattern -- OutPattern, Goal),
Stack0 = InPattern,
call(Goal),
Stack = OutPattern.
% Program runtime is deliberately unchanged from Stage 01. Only
% one-word execution changed. The recursive walk still threads the
% middle stack through the rest of the program.
run([], Stack, Stack).
run([Word|Words], Stack0, Stack) :-
apply(Word, Stack0, Stack1),
run(Words, Stack1, Stack).
% Inference projects the same stack equation without calling the
% runtime goal. The omission is the point: a type checker should learn
% the stack shape of a word without performing the word's computation.
infer([], Stack, Stack).
infer([Word|Words], Stack0, Stack) :-
word(Word, InPattern -- OutPattern, _Goal),
Stack0 = InPattern,
Stack1 = OutPattern,
infer(Words, Stack1, Stack).
```