sicp.io
5.5.7 · Compiled code meets the evaluator

One apply boundary can connect two procedure representations.

An evaluator can call compiled procedures and compiled code can call interpreted procedures when both share one environment model and argument convention.

Guiding question

Which runtime agreements let interpreted and compiled procedures call across their representation boundary without pretending they are the same object?

  • Keep interpreted and compiled procedures as distinct tagged representations
  • Share one lexical environment and argument-list convention
  • Route primitive, interpreted, and compiled procedures through one apply boundary
  • Call compiled code from the evaluator
  • Call an interpreted procedure from compiled code
  • Record the actual representation dispatch order for both directions
  • Describe the shared apply boundary through its environment, argument, and dispatch contracts

The shared global environment stores wrapped primitives, one interpreted procedure named double, and one compiled procedure named add-three. evaluate creates interpreted closures whose bodies remain expression data. compile-expression creates stack-machine code and closure instructions whose bodies are instruction lists. The two representations remain visibly different, but both carry parameters and a lexical environment and both accept the same ordered argument list.

apply-any is the interface. An evaluator application reaches it after evaluating an operator and operands. A compiled call instruction reaches the same boundary after popping its procedure and arguments from the VM stack. The evaluator-to-compiled run records (compiled primitive): add-three enters compiled code, whose addition calls a primitive. The compiled-to-evaluator run records (interpreted primitive): compiled code calls double, whose interpreted body multiplies through a primitive. The lesson model records the exact cross-call contract for both directions.

SICP code11,508 of 1,048,576 UTF-8 bytes
Examples
Result
Output
Value
Diagnostic
Execution trace0 / 0 events
    Programs run in the browser with their result and execution trace.
    Expected result

    The program returns ((evaluator-to-compiled 8 (compiled primitive)) (compiled-to-evaluator 14 (interpreted primitive) #t) (representations #t #t)). The dispatch lists record the actual procedure representations entered by each selected run.

    Trace focus

    First follow evaluator lookup of add-three into apply-any, then the compiled closure’s VM lookup and primitive call. Next follow the compiled call instruction for double into the interpreted branch, environment extension, expression-body evaluation, and primitive multiplication. Confirm that both paths use the same global environment and ordered argument convention while preserving distinct interpreted and compiled procedure tags.

    Try it yourself

    Change the program and compare the result.

    Add an interpreted procedure that calls add-three and compile a procedure that calls double. Invoke both wrappers and predict the nested dispatch logs before running them.

    Show hint

    Each wrapper adds its own representation to the front of the chronological path. Follow the outer call first, then the representation entered by its body.

    Complete this lesson

    0 of 23 lessons complete in this chapter0%