# Lesson IX A stroke begins by knowing where it will appear. ## Try ```prolog ?- empty_env(E), infer(E, [push(quote([dup, mul])), call], Effect). Effect = effect([int|S], [int|S]). ?- empty_env(E), run(E, [push(int(4)), push(quote([dup, mul])), call], [], Stack). Stack = [int(16)]. ``` ## Learn We made the environment an explicit argument everywhere a program can run, infer, or validate a literal. The old arities are changed because an implicit empty context would not scale to user definitions or environment-backed declarations. > [!info]- Change > ```diff > - run([], Stack, Stack). > - run([Word|Words], Stack0, Stack) :- > - apply(Word, Stack0, Stack1), > - run(Words, Stack1, Stack). > - > - apply(Word, Stack0, Stack) :- > - word(Word, InPattern -- OutPattern, Goal), > - bind(InPattern, Stack0), > - call(Goal), > - build(OutPattern, Stack). > - apply(push(Value), Stack, [Value|Stack]) :- > - lit(Value, _Type). > - apply(call, [quote(Words)|Stack0], Stack) :- > - run(Words, Stack0, Stack). > - > - infer([], effect(Stack, Stack)). > - infer([Word|Words], effect(Stack0, Stack)) :- > - infer1(Word, Stack0, Stack1), > - infer(Words, effect(Stack1, Stack)). > - > - infer1(push(Value), Stack, [Type|Stack]) :- > - !, > - lit(Value, Type). > - infer1(call, [quote(Effect)|Stack0], Stack) :- > - !, > - copy_term(Effect, effect(Stack0, Stack)). > - infer1(Word, Stack0, Stack) :- > - word(Word, InPattern -- OutPattern, _Goal), > - types(InPattern, Stack0), > - types(OutPattern, Stack). > - > - types([Item|Items], [Type|Types]) :- > - typed(Item, _Payload, Type), > - !, > - types(Items, Types). > - > - typed(Item, Payload, Type) :- > - nonvar(Item), > - Item = (Payload::Type). > - > - bind([Item|Patterns], [Value|Values]) :- > - typed(Item, Payload, Type), > - !, > - unpack(Type, Value, Payload), > - bind(Patterns, Values). > - > - build([Item|Patterns], [Value|Values]) :- > - typed(Item, Payload, Type), > - !, > - pack(Type, Payload, Value), > - build(Patterns, Values). > - > - lit(int(Int), int) :- > - integer(Int). > - lit(quote(Words), quote(effect(In, Out))) :- > - infer(Words, effect(In, Out)). > ``` Runtime sequencing is ordinary stack threading over a word list. ```prolog run(_, [], Stack, Stack). run(Env, [Word|Words], Stack0, Stack) :- apply(Env, Word, Stack0, Stack1), run(Env, Words, Stack1, Stack). ``` Fixed words project through primitive rows. `push/1` validates a literal and puts it on the runtime stack unchanged. ```prolog apply(_Env, Word, Stack0, Stack) :- word(Word, InPattern -- OutPattern, Goal), bind(InPattern, Stack0), call(Goal), build(OutPattern, Stack). apply(Env, push(Value), Stack, [Value|Stack]) :- lit(Env, Value, _Type). apply(Env, call, [quote(Words)|Stack0], Stack) :- run(Env, Words, Stack0, Stack). ``` Static sequencing publishes an input stack and an output stack. Public inference now returns an `effect/2` term. That term can appear by itself or inside the type of a quotation. ```prolog infer(_, [], effect(Stack, Stack)). infer(Env, [Word|Words], effect(Stack0, Stack)) :- infer1(Env, Word, Stack0, Stack1), infer(Env, Words, effect(Stack1, Stack)). ``` `push/1` contributes the literal's type to the static stack. ```prolog infer1(Env, push(Value), Stack, [Type|Stack]) :- !, lit(Env, Value, Type). infer1(_Env, call, [quote(Effect)|Stack0], Stack) :- !, copy_term(Effect, effect(Stack0, Stack)). infer1(_Env, Word, Stack0, Stack) :- word(Word, InPattern -- OutPattern, _Goal), types(InPattern, Stack0), types(OutPattern, Stack). ``` `lit/3` is the only way a literal enters runtime or inference. ```prolog types([_Payload::Type|Items], [Type|Types]) :- !, types(Items, Types). bind([Payload::Type|Patterns], [Value|Values]) :- !, unpack(Type, Value, Payload), bind(Patterns, Values). build([Payload::Type|Patterns], [Value|Values]) :- !, pack(Type, Payload, Value), build(Patterns, Values). ``` A quotation is valid when its body has a static stack effect. ```prolog lit(_Env, int(Int), int) :- integer(Int). lit(Env, quote(Words), quote(effect(In, Out))) :- infer(Env, Words, effect(In, Out)). ``` Declare an empty context. ```prolog empty_env(env([])). ``` [[08_lesson|Prev]] | [[10_lesson|Next]]