Skip to content

Commit

Permalink
Complete conclusions
Browse files Browse the repository at this point in the history
  • Loading branch information
noelwelsh committed Nov 22, 2023
1 parent 56d3311 commit 9736d11
Showing 1 changed file with 10 additions and 11 deletions.
21 changes: 10 additions & 11 deletions src/pages/adt-interpreters/conclusions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,20 @@ In this chapter we've discussed why we might want to build interpreters, and see
To recap, the core of the interpreter strategy is a separation between description and action.
The description is the program, and the interpreter is the action that carries out the program.
This separation is allows for composition of programs, and managing effects by delaying them till the time the program is run.
We sometimes call this structure an algebra.
We sometimes call this structure an algebra, with constructs and combinators defining programs and destructors defining interpreters.
Although the name of the strategy focuses on the interpreter, the design of the program is just as important as it is the user interface through which the programmer interacts with the system.

Our starting implementation technique is reification of the algebra's constructors and compositional methods as an algebraic data type. The interpreter is then a structural recursion over this ADT.
Our starting implementation strategy is reification of the algebra's constructors and compositional methods as an algebraic data type. The interpreter is then a structural recursion over this ADT.
We saw that the straightforward implementation is not stack-safe, and which caused us to introduction the idea of tail recursion and continuations.
We reified continuations as functions, and saw that we can convert any program into continuation-passing style which has every method call in tail position.
Due to Scala runtime limitations not all calls in tail position can be converted to tail calls, so we reified calls and returns these data structures to a recursive loop called a trampoline.
Due to Scala runtime limitations not all calls in tail position can be converted to tail calls, so we reified calls and returns into data structures used by a recursive loop called a trampoline.
Underlying all these strategies in the concept of duality. We have seen a duality between functions and data, which we utilize in reification, and a duality between calling functions and returning data, which we use in continuations and trampolines.

These ideas are classics in programming language theory.
[Definitional Interpreters for Higher-Order Programming Languages][defn], which was first published in 1972 though I link to the re-typeset version from 1998, details defunctionalization, a limited form of reification, and continuation passing style.
These ideas are expanded on in [Defunctionalization at Work][at-work].
[Continuation-Passing Style, Defunctionalization, Accumulations, and Associativity][assoc] is a very readable and elegant paper that highlights the importance of associativity in these transformations.

Continuation-Passing Style, Defunctionalization, Accumulations, and Associativity
https://www.cs.ox.ac.uk/jeremy.gibbons/publications/continued.pdf

Definitional Interpreters for Higher-Order Programming Languages
https://homepages.inf.ed.ac.uk/wadler/papers/papers-we-love/reynolds-definitional-interpreters-1998.pdf

Defunctionalization at Work
https://www.brics.dk/RS/01/23/BRICS-RS-01-23.pdf
[defn]: https://homepages.inf.ed.ac.uk/wadler/papers/papers-we-love/reynolds-definitional-interpreters-1998.pdf
[at-work]: https://www.brics.dk/RS/01/23/BRICS-RS-01-23.pdf
[assoc]: https://www.cs.ox.ac.uk/jeremy.gibbons/publications/continued.pdf

0 comments on commit 9736d11

Please sign in to comment.