# 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). ```