# Lesson IV
The eye and the 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
Runtime and inference must agree on primitive stack effects; otherwise, two separately maintained terms can drift. `word/3` replaces the old `sig/3` rows with equations. Runtime and inference both project from one primitive source while still asking different questions of it.
> [!info]- Change
> ```diff
> - apply(dup, [A|S], [A, A|S]).
> - apply(drop, [_|S], S).
> - apply(swap, [A, B|S], [B, A|S]).
> - apply(over, [A, B|S], [B, A, B|S]).
> -
> - sig(dup, [A|S], [A, A|S]).
> - sig(drop, [_|S], S).
> - sig(swap, [A, B|S], [B, A|S]).
> - sig(over, [A, B|S], [B, A, B|S]).
> -
> - infer([Word|Words], Stack0, Stack) :-
> - sig(Word, Stack0, Stack1),
> - infer(Words, Stack1, Stack).
> ```
A primitive equation is the shared one-word fact both projections need:
* the input stack pattern;
* the output stack pattern;
* the runtime goal to run between them.
The four shufflers have `true` as their runtime goal because they only move stack cells. Their whole behavior is already captured by unifying the input and output patterns. The `--/2` operator is ordinary Prolog syntax. It gives a stack transition a visual shape without introducing a separate parser.
```prolog
:- 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 selects a row, matches the actual stack against the row's input pattern, calls the row's goal, and returns the row's output pattern. For now matching is just unification because stack shufflers do not inspect or validate types.
```prolog
apply(Word, Stack0, Stack) :-
word(Word, InPattern -- OutPattern, Goal),
Stack0 = InPattern,
call(Goal),
Stack = OutPattern.
```
Inference projects the same stack equation without calling the runtime goal. A type checker should learn the stack shape of a word without performing the word's computation.
```prolog
infer([], Stack, Stack).
infer([Word|Words], Stack0, Stack) :-
word(Word, InPattern -- OutPattern, _Goal),
Stack0 = InPattern,
Stack1 = OutPattern,
infer(Words, Stack1, Stack).
```
[[03_lesson|Prev]] | [[05_lesson|Next]]