# Lesson VI The drop shows its form; the brush sets it down. ## Try ```prolog ?- run([push(int(2)), push(int(3)), add], [], Stack). Stack = [int(5)]. ?- infer([push(int(2)), push(int(3)), add], In, Out). In = [], Out = [int]. ?- run([push(int(foo))], [], Stack). false. ``` ## Learn Until now an object-language integer has been the same bare Prolog integer used by arithmetic. Remove that shortcut: stack values become explicit, such as `int(N)`, and value introduction is routed through `push` and `lit`. The old identity `pack/3` and `unpack/3` clauses are changed because they blurred a design boundary: primitives compute with host payloads, but the stack stores language values. > [!info]- Change > ```diff > - infer([Word|Words], Stack0, Stack) :- > - word(Word, InPattern -- OutPattern, _Goal), > - types(InPattern, Stack0), > - types(OutPattern, Stack1), > - infer(Words, Stack1, Stack). > - > - unpack(int, Value, Value) :- > - integer(Value). > - > - pack(int, Payload, Payload) :- > - integer(Payload). > ``` `push/1` validates a literal and puts it on the runtime stack unchanged. ```prolog apply(push(Value), Stack, [Value|Stack]) :- lit(Value, _Type). ``` `push/1` contributes the literal's type to the static stack. ```prolog infer([Word|Words], Stack0, Stack) :- infer1(Word, Stack0, Stack1), infer(Words, Stack1, Stack). infer1(push(Value), Stack, [Type|Stack]) :- !, lit(Value, Type). infer1(Word, Stack0, Stack) :- word(Word, InPattern -- OutPattern, _Goal), types(InPattern, Stack0), types(OutPattern, Stack). ``` `lit/2` is the only way a literal enters runtime or inference. ```prolog unpack(int, int(Int), Int) :- integer(Int). pack(int, Payload, int(Payload)) :- integer(Payload). lit(int(Int), int) :- integer(Int). ``` [[05_lesson|Prev]] | [[07_lesson|Next]]