Operational Semantics with Hierarchical Abstract Syntax Graphs
PP. Bahr (Ed.): 11th International Workshop onComputing with Terms and Graphs (TERMGRAPH 2020)EPTCS 334, 2021, pp. 1–10, doi:10.4204/EPTCS.334.1 © Dan R. GhicaThis work is licensed under theCreative Commons Attribution License.
Operational Semantics withHierarchical Abstract Syntax Graphs *Dan R. Ghica
Huawei Research, EdinburghUniversity of Birmingham, UK
This is a motivating tutorial introduction to a semantic analysis of programming languages using agraphical language as the representation of terms, and graph rewriting as a representation of reduc-tion rules. We show how the graphical language automatically incorporates desirable features, suchas α -equivalence and how it can describe pure computation, imperative store, and control features ina uniform framework. The graph semantics combines some of the best features of structural oper-ational semantics and abstract machines, while offering powerful new methods for reasoning aboutcontextual equivalence.All technical details are available in an extended technical report by Muroya and the author [11]and in Muroya’s doctoral dissertation [21]. Before proceeding with the business of analysing and transforming the source code of a program, a com-piler first parses the input text into a sequence of atoms, the lexemes , and then assembles them into atree, the
Abstract Syntax Tree (AST), which corresponds to its grammatical structure. The reason forpreferring the AST to raw text or a sequence of lexemes is quite obvious. The structure of the AST incor-porates most of the information needed for the following stage of compilation, in particular identifyingoperations as nodes in the tree and operands as their branches. This makes the AST algorithmically wellsuited for its purpose. Conversely, the AST excludes irrelevant lexemes, such as separators (white-space,commas, semicolons) and aggregators (brackets, braces), by making them implicit in the tree-like struc-ture. It is always possible to recover the textual input, or rather an equivalent version of it, from the ASTvia a process known as pretty-printing .A fair question to ask is whether the AST can be improved upon as a representation of program text,which captures grammatical structure while discarding needless detail. In pretty-printing we know howirrelevant lexemes can be manipulated to achieve a certain aesthetic effect. Redundant brackets can beelided to reduce clutter, white-space can be added or removed to improved alignment, and so on. Suchdetails are accepted as irrelevant.There is another, deeper level of detail in the text, which is irrelevant but not always appreciated assuch: variable names. Whereas we know, formally, that bound variables can be systematically renamed( α -equivalence ) the conventional AST will still remember their names, even though variable namesinduce bureaucratic complications having to do with scope and shadowing. Finally, there is yet anothereven deeper level of irrelevant detail in the program text, the order in which variables are defined, absentdefine-use dependencies between the definitions.Consider the program text in Fig. 1, in which def is a binder associating a variable with a definitionas text, akin to a macro, but respecting variable scoping rules. Variable x in line 3 could be renamed, on * Extended abstract of invited talk
Operational Semantics with Hierarchical ASGs defx 0 defy +x 1 defx 2 defz + +x 3 y z +0 1 ++ 2 3 y zx x
Figure 2: AST vs ASG for variable definitionlines 3-5, to something else to avoid shadowing the variable with the same name on line 1. Lines 1-2 andlines 3-4 can be swapped without changing the result. But these facts are not immediate from examiningits AST in Fig 2 (left). def x = 0 def y = x + 1 def x = 2 def z = x + 3 y + z Figure 1: Bindings Unlike ASTs, an abstract syntax graphs (ASG) do not treatbinders and variables as nodes. Variables are instead representedas links, and binders assign target nodes corresponding to theirdefinitions to the variable links. The ASG of the code in Fig. 1is represented next to its AST in Fig. 2. To better understandthe relation between the AST and the ASG, corresponding nodesare coloured and the links are labelled with variable names. Thecolour and the labels are not part of the definition of the graphstructure, but are just used to aid understanding. The nodes cor-responding to variable uses and definitions, left blank, are not part of the ASG. It is thus immediatelyobvious that the ASG is, by construction, quotiented both by α -equivalence and by the order of non-interfering variable bindings. This more general structural equivalence of lambda calculus terms hasbeen dubbed “graph equivalence” by Accattoli et. al. [4]. def x = 2 def z = x + 3 z + z Figure 3: Contraction ASGs are also helpful when variables are reused, as in theFig. 3 example. The AST and the ASG are showed side-by-sidein Fig. 2, noting that the links corresponding to the variable z ,used twice, now both point to its definition. This is why ASG areno longer trees, but directed acyclic graphs (DAGs). Formally, theASGs are hypergraphs with the links a graphical representation ofvertices and the nodes a graphical representation of hyperedges.To represent local variable binding, as encountered in functions as opposed to simple variable def-inition discussed above, we note that local variable binding is always associated with thunks , i.e. codewith delayed execution. This is related to the fact that conventional programming languages use normal-order reduction. In this evaluation strategy functions are considered values, i.e. there is no evaluation‘under the lambda’. In other words, functions are thunks and locally-bound variables will always inducea thunk. Because thunks can be considered, operationally, as a single entity, it is convenient to representthem in their ASG form as a single node, labeled by the definition of the thunk, which is also an ASG.In other words, to model local variable binding in functions it is convenient to use graphs labelled bygraphs, which are, formally, hierarchical hypergraphs. an R. Ghica defx 2 defz + +x 3 z z ++ 32 z zx Figure 4: AST vs ASG for contraction λ x . x + x + λ f λ x . f ( f x ) λ x . ( xx )( xx ) λ λ λλ + + Figure 5: Hierarchical ASGsTo model variable behaviour in thunks correctly, our ASGs need to be interfaced , i.e. there needsto be a defined order on incoming links. If a thunk has m bound variables and n free variables then thefirst m incoming links of the ASG used as its label represent the bound variables, in the order in whichthey are bound. The last n incoming links represent the free variables, in some specified order. Thenode corresponding to the thunk will also have n incoming links, representing the definitions of its n freevariables, in an order consistent with the order used by the label ASG. To make the correspondence moreperspicuous we connect the links corresponding to the free variables from the labelling ASG to thoseof the node, as it causes no ambiguity. Fig. 5 shows several examples for hierarchical ASGs and thecorresponding terms, with function application labelled as @. Note that thunks associated with lambdaexpressions are still explicitly linked to a lambda-labelled node. This is because in a programminglanguage thunks can be used for expressions other than function definitions, as we shall see. The most widely used method for specifying programming languages is via operational semantics (OS).There are several versions of OS. We will focus on so-called structural operational semantics (SOS) inthe style of Plotkin [27], in which a transition relation is defined on configurations consisting of a term t and some additional information (e.g. a program store , s , t ), so that the definition of the relation isinductive on the structure of the term. Operational Semantics with Hierarchical ASGs
F F λ @ Figure 7: ASG rewrite as basic reductions s , + → s , s , e → s (cid:48) , e (cid:48) s , e + e → s (cid:48) , e (cid:48) + e . Figure 6: SOS (example rules)Typically the transition relation is written as s , t → s (cid:48) , t (cid:48) . Thereare two kinds of rules, basic reductions which perform operations(e.g. first rule in Fig. 6) and simplification steps which seek re-dexes structurally in the program text according to the evaluationstrategy (second rule in Fig. 6). The latter are usually written innatural-deduction style. For example, the rule specifying that + is evaluated left-to-right is the second rule in Fig. 6. Note how thefirst operand e is evaluated to e (cid:48) and, in the proces, the store s may change to s (cid:48) .SOS can be naturally formulated on ASGs rather than on terms. Basic reductions correspond tograph rewrites and simplification steps to a graph traversal algorithm which seeks the redexes. The basicreduction in Fig. 6 is shown as a graph rewrite in Fig. 7, along with the rule for β -reduction. The formeris quite obvious, but the latter is more interesting. It consists of the deletion of the abstraction-applicationpair, the ‘unboxing’ of the thunk by extracting the label of the thunk node and using it in the top-levelgraph, the re-wiring of the bound variable, now open, to the argument, and using the root node of F asthe overall root node. For the β rule the graphs involved in the rewrite must also be interfaced, with theinterface nodes highlighted in grey. Also note that the rule is actually the small β rule used in calculi ofexplicit substitution which reduces ( λ x . F ) M to def x = M in F [1].One aspect of the ASG-based evaluation which needs to be clearly explicated is sharing. The DAGstructure of the ASG can be refined by introducing special sharing nodes, which, unlike operation nodes,would be allowed to have multiple incoming links. Sharing nodes have a special behaviour duringevaluation, managing the process of systematic copying of sub-graphs.To evaluate an ASG in a way that is consistent with left-to-right call-by-value the traversal is depth-first and left-to-right, without reaching inside thunks, starting from the unique root. The current link inthe traversal is called the focus , and it can move up (i.e. away from the root) or down (i.e. towards theroot). When the focus is moving up and it encounters a copy node it will copy the node shared by thecopy node, inserting further copy nodes on its outgoing links. As the focus is moving down, whenever itpasses a node which has an associated rewrite rule it will exercise it, then change direction and move upagain ( refocussing ).In Fig. 8 we show the key steps in the evaluation of the expression ( λ f x . f ( f x )))( λ x . x + , ) . Weuse the labels of λ abcbdefa , at which point the rewrite is performed, unboxing thethunk and attaching the arguments to the nodes made available. Step (2) is simply rearranging the ASGin a more readable format. Step (3) is the copying of the node corresponding to the function λ x . x + an R. Ghica abc de f aba c d (1) (2)(3) (4) (5) (6) (7)@ @ λ + λ @ @ + λ + λ @ @ 2 + λ @ @ 2 + λ + λ @ + + λ @ 3 3 + b Figure 8: Evaluation of ( λ f x . f ( f x )))( λ x . x + , ) .after the focus traverses path ab . Step (4) is the β rewrite applied after the focus traverses path abcdb .Step (5) is an arithmetic reduction, followed by another β rewrite and a final arithmetic reduction.The examples in this section (abstraction, application, arithmetic) deal with what is usually deemed pure functional programming, case in which the configuration used by the SOS is the term itself. Expand-ing the SOS of a language to incorporate effects usually requires revising the format of the configurationof the SOS, which in turn requires reformulating the rules for the preexisting operations. This is a ma-jor fragility of the SOS approach, since the revision of the format invalidates any technical results andrequire laborious re-proving [12]. ASGs can be enhanced with a single new node which will allow theformulation of most known effects, namely an atom node, in the sense of [26]. The ASG OS for apure language then only differs from the ASG OS of an impure language in that the atom nodes are notinvolved. The atom node, just like a sharing node, allows multiple incoming links. However, duringevaluation, the atom node does not trigger a copying of the node at the end of its outgoing link, but isinstead treated as an endpoint by the ASG traversal strategy. Indeed, just as computations are not per-formed inside of thunks they are also not performed inside of the store. This insight, that the essence ofeffectful computation is the presence of atoms in the OS is originally due to Pitts, but it turns out to bemost effective in ASG-based OS [24].Fig 9 shows the basic rule for assignment, with the atom indicated as an unlabeled white node. Theatom is made to point to the second operand of the assignment operator, while the assignment operatoritself reduces to the dummy value inhabiting the unit type. In the process, whatever the atom was attachedto before may become inaccessible from the root of the ASG, therefore garbage. Also note that the effect
Operational Semantics with Hierarchical ASGs l M M ; l M Mb ; l M • Mc ; l M l M Figure 10: Control in ASG OSof the assignment is manifest only because other parts of the ASG may point to the atom, a link which ispersistent due to the value-like behaviour of the atom. : = M • M Figure 9: Assignment in ASG OSThe SOS of a programming language canbe further refined ( distilled ) into an abstract ma-chine, which gives a more explicit representa-tion of the simplification rules via manipulationof context [31]. From this point of view, theASG representation of the SOS is already an ab-stract machine, in the sense that it can give a cost-accurate model of execution of the language.Another appealing feature of abstract ma-chines is that they can model control-transfer op-erations more conveniently that SOS. It is not im-possible to use SOS for this, but the format of the transition system needs to be significantly revised,making the transitions themselves labelled [29].Since the ASG OS is formulated via arbitrary rewrites, control can be dealt with in a straightforwardway. Fig 10 shows a labelled version of C-style break/continue statements. The operations involvedare loop body definition ( l ), sequential composition (;), break ( b ), and continue ( c ). The atom used asthe first operand of l becomes bound to the label which is the bound argument of M , used to anchor apoint in the ASG so that the control operations of break or continue can determine where to jump to. If M terminates normally then the whole cycle repeats. Unlike conventional C break and continue thesevariants are labelled, and the labels are first-class citizens, i.e. they can be passed as arguments to orreturned from functions.An interactive evaluator for a variety of programming language features can be found online. . SOS was originally considered too ‘low level’ to reason about equivalence in programming languages,at least in contrast with denotational semantics. However, SOS was considered more ‘high level’ thanalternative operational specifications of programming languages such as abstract machines. In time, alarge variety of powerful techniques for reasoning with SOS-like specifications proved that this is indeeda useful formalism for reasoning about equivalence [25] whereas abstract machines remained useful due https://tnttodda.github.io/Spartan-Visualiser/ an R. Ghica deterministic and refocussing . The first concept is the standard one. The second, initially formulated byDanvy et. al., means that following a basic reduction the focus could be kept either at the point wherethe rewrite occurs, or moved to the root of the graph, with equal effect [9]. Indeed, all the rules we havepresented in this tutorial are refocussing.Equivalences are also formulated graphically, as families of relations on templates , i.e. sets of graphswith the same interface. For a fixed abstract machine a template is said to be input-safe if evaluationfrom any input link preserves the relation. Note that, unlike a SOS, we can talk about the evaluation ofan ASG which is not a program, in fact not even a term, since evaluation is just a byword for traversal andreduction. A template is said to be output-closed if in the course of evaluation no output link will everbe reached. Finally, a template is said to be robust if it is preserved by all rewrite rules of the language.The main theorem can be simply stated as: Theorem. (Characterisation [11, Sec. 6]).
Robust templates induce observational equivalence.
The conditions used to establish equivalence via the Characterisation Theorem are all elementary andproved by case analysis. Moreover, the theorem allows for robust proofs of equivalence in the sense thatthey can withstand language extensions. For example we can prove the β law for a pure language canbe extended to a language with imperative store just by showing that the templates used in formulatingthe law are robust relative to the new rules for variable creation, dereferencing, and assignment (Fig. 4).Which happens to be the case. By contrast, conventional proofs of equivalence are fragile, and areinvalidated by even mild language extensions. This is an elementary tutorial introduction and extended motivation for the hypernet semantics of pro-gramming languages [11], which is a streamlined and generalised version of the
Dynamic Geometry ofInteraction (GoI) Machine [22]. They are the outcome of an effort initially motivated by the understand-ing of call-by-value and effectful computation from a GoI perspective [16, 23].Graph-based intermediate representations (IR) are established in compiler construction [7] and inthe formulation of abstract machines for functional languages [17]. However, the origin of the approachdescribe here lies elsewhere, in proof nets , a graphical representation of proofs in Linear Logic [13] andespecially in their generalisation as interaction nets [18]. Interaction nets already exhibit the hierarchicalstructure we employ here, which is used to model binding and higher-order structures. Hierarchicalgraphs are also used elsewhere in semantics, for example as diagram languages of processes known as bigraphs [20].The connection between linear logic and its varieties and certain monoidal categories kindled signif-icant progress in diagrammatic languages [30]. For instance, traced monoidal categories, used as modelsof lambda calculus with cyclic sharing [15], led to the development of a hierarchical graph syntax forclosures [28] remarkably similar to the one described here. In terms of the treatment of graphs as com-binatorial objects, much of the literature considered them rather informally and a formalisation of proof
Operational Semantics with Hierarchical ASGs nets as hypergraphs was given much later [14].More recently, work by Accattoli has examined the interesting interplay between term-based andgraph-based formulations of the call-by-value lambda calculus [2], even though his motivations aresomewhat different than ours, as illustrated by this quotation:
It is far from easy to realize an isomorphism between terms and nets, as it is neces-sary to take care of many delicate details about weakenings, contractions, representationof variables, administrative reduction steps, and so on. [ . . . ] More generally, such a strongrelationship turns the calculus into an algebraic language for proof nets, providing a handytool to reason by structural induction over proof nets.
In fact, a properly formalised graphical syntax can be just as powerful and just as rigorous as an algebraiclanguage. Moreover, the graphical language can be both simpler and better specified than the term lan-guage, for example in the case of the calculus of explicit substitutions, which lacks a proper formulationof α -equivalence [3].To conclude, we see the ASG operational semantics as a first step in an exciting and potentially fruit-ful direction. Graphical languages are starting to emerge as a new and genuine formalism which cangive alternative, and sometimes improved, representations to theories in fields as different as quantumcomputation [8], linear and affine algebra [5], digital circuits [10], signal flow [6] and more. The moti-vations for this emergence are mixed, from the raw intuitive appeal of visual representations to improvedalgorithmic properties. Examining how this methodology can be extended to programming languagesis an intriguing next step which brings together a number of existing ideas and concepts and can unifyexisting gaps between semantics of programming languages and compiler-related techniques. References [1] Mart´ın Abadi, Luca Cardelli, Pierre-Louis Curien & Jean-Jacques L´evy (1991):
Explicit Substitutions . J.Funct. Program.
Proof nets and the call-by-value λ -calculus . Theor. Comput. Sci.
Proof Nets and the Linear Substitution Calculus . In Bernd Fischer & TarmoUustalu, editors:
Theoretical Aspects of Computing - ICTAC 2018 - 15th International Colloquium, Stellen-bosch, South Africa, October 16-19, 2018, Proceedings , Lecture Notes in Computer Science
A nonstandard standard-ization theorem . In Suresh Jagannathan & Peter Sewell, editors:
The 41st Annual ACM SIGPLAN-SIGACTSymposium on Principles of Programming Languages, POPL ’14, San Diego, CA, USA, January 20-21,2014 , ACM, pp. 659–670, doi:10.1145/2535838.2535886.[5] Filippo Bonchi, Robin Piedeleu, Pawel Sobocinski & Fabio Zanasi (2019):
Graphical Affine Algebra . In: , IEEE, pp. 1–12, doi:10.1109/LICS.2019.8785877.[6] Filippo Bonchi, Pawel Sobocinski & Fabio Zanasi (2015):
Full Abstraction for Signal Flow Graphs . InSriram K. Rajamani & David Walker, editors:
Proceedings of the 42nd Annual ACM SIGPLAN-SIGACTSymposium on Principles of Programming Languages, POPL 2015, Mumbai, India, January 15-17, 2015 ,ACM, pp. 515–526, doi:10.1145/2676726.2676993.[7] Cliff Click & Michael Paleczny (1995):
A Simple Graph-Based Intermediate Representation . In Michael D.Ernst, editor:
Proceedings ACM SIGPLAN Workshop on Intermediate Representations (IR’95), San Fran-cisco, CA, USA, January 22, 1995 , ACM, pp. 35–49, doi:10.1145/202529.202534. an R. Ghica [8] Bob Coecke & Aleks Kissinger (2017): Picturing Quantum Processes: A First Course in Quantum Theoryand Diagrammatic Reasoning . Cambridge University Press, doi:10.1017/9781316219317.[9] Olivier Danvy, Kevin Millikin, Johan Munk & Ian Zerny (2012):
On inter-deriving small-step and big-step semantics: A case study for storeless call-by-need evaluation . Theor. Comput. Sci.
Diagrammatic Semantics for Digital Circuits . InValentin Goranko & Mads Dam, editors: , LIPIcs
82, Schloss Dagstuhl - Leibniz-Zentrum f¨urInformatik, pp. 24:1–24:16, doi:10.4230/LIPIcs.CSL.2017.24.[11] Dan R. Ghica, Koko Muroya & Todd Waugh Ambridge (2019):
Local Reasoning for Robust ObservationalEquivalence . CoRR abs/1907.01257. Available at http://arxiv.org/abs/1907.01257 .[12] Dan R. Ghica & Nikos Tzevelekos (2012):
A System-Level Game Semantics . In Ulrich Berger & Michael W.Mislove, editors:
Proceedings of the 28th Conference on the Mathematical Foundations of ProgrammingSemantics, MFPS 2012, Bath, UK, June 6-9, 2012 , Electronic Notes in Theoretical Computer Science
Linear Logic . Theor. Comput. Sci.
50, pp. 1–102, doi:10.1016/0304-3975(87)90045-4.[14] Stefano Guerrini, Simone Martini & Andrea Masini (2001):
Proof nets, garbage, and computations . Theor.Comput. Sci.
Recursion from Cyclic Sharing: Traced Monoidal Categories and Models ofCyclic Lambda Calculi . In Philippe de Groote, editor:
Typed Lambda Calculi and Applications, ThirdInternational Conference on Typed Lambda Calculi and Applications, TLCA ’97, Nancy, France, April 2-4,1997, Proceedings , Lecture Notes in Computer Science
Memoryful geometry of interaction: from coalge-braic components to algebraic effects . In Thomas A. Henzinger & Dale Miller, editors:
Joint Meeting of theTwenty-Third EACSL Annual Conference on Computer Science Logic (CSL) and the Twenty-Ninth AnnualACM/IEEE Symposium on Logic in Computer Science (LICS), CSL-LICS ’14, Vienna, Austria, July 14 -18, 2014 , ACM, pp. 52:1–52:10, doi:10.1145/2603088.2603124.[17] Simon L. Peyton Jones & Jon Salkild (1989):
The Spineless Tagless G-Machine . In Joseph E.Stoy, editor:
Proceedings of the fourth international conference on Functional programming languagesand computer architecture, FPCA 1989, London, UK, September 11-13, 1989 , ACM, pp. 184–201,doi:10.1145/99370.99385.[18] Yves Lafont (1990):
Interaction Nets . In Frances E. Allen, editor:
Conference Record of the Seventeenth An-nual ACM Symposium on Principles of Programming Languages, San Francisco, California, USA, January1990 , ACM Press, pp. 95–108, doi:10.1145/96709.96718.[19] Xavier Leroy (1990):
The ZINC experiment : an economical implementation of the ML language . TechnicalReport RT-0117, INRIA. Available at https://hal.inria.fr/inria-00070049 .[20] Robin Milner (2008):
Bigraphs and Their Algebra . Electron. Notes Theor. Comput. Sci.
Hypernet Semantics of Programming Languages . Ph.D. thesis, University of Birm-ingham. Available at .[22] Koko Muroya & Dan R. Ghica (2019):
The Dynamic Geometry of Interaction Machine: A Token-GuidedGraph Rewriter . Log. Methods Comput. Sci. https://lmcs.episciences.org/5882 .[23] Koko Muroya, Naohiko Hoshino & Ichiro Hasuo (2016):
Memoryful geometry of interaction II: recursionand adequacy . In Rastislav Bod´ık & Rupak Majumdar, editors:
Proceedings of the 43rd Annual ACMSIGPLAN-SIGACT Symposium on Principles of Programming Languages, POPL 2016, St. Petersburg, FL,USA, January 20 - 22, 2016 , ACM, pp. 748–760, doi:10.1145/2837614.2837672. Operational Semantics with Hierarchical ASGs [24] Andrew M. Pitts (1996):
Reasoning about Local Variables with Operationally-Based Logical Relations . In:
Proceedings, 11th Annual IEEE Symposium on Logic in Computer Science, New Brunswick, New Jersey,USA, July 27-30, 1996 , IEEE Computer Society, pp. 152–163, doi:10.1109/LICS.1996.561314.[25] Andrew M. Pitts (2000):
Operational Semantics and Program Equivalence . In Gilles Barthe, Peter Dyb-jer, Lu´ıs Pinto & Jo˜ao Saraiva, editors:
Applied Semantics, International Summer School, APPSEM 2000,Caminha, Portugal, September 9-15, 2000, Advanced Lectures , Lecture Notes in Computer Science
Nominal Sets: Names and Symmetry in Computer Science . Cambridge Tracts inTheoretical Computer Science, Cambridge University Press, doi:10.1017/CBO9781139084673.[27] Gordon D. Plotkin (2004):
A structural approach to operational semantics . J. Log. Algebraic MethodsProgram.
A Categorical and Graphical Treatment of Closure Conversion .In Stephen D. Brookes, Achim Jung, Michael W. Mislove & Andre Scedrov, editors:
Fifteenth Conferenceon Mathematical Foundations of Progamming Semantics, MFPS 1999, Tulane University, New Orleans, LA,USA, April 28 - May 1, 1999 , Electronic Notes in Theoretical Computer Science
20, Elsevier, pp. 481–511,doi:10.1016/S1571-0661(04)80090-2.[29] Neil Sculthorpe, Paolo Torrini & Peter D. Mosses (2015):
A Modular Structural Operational Semanticsfor Delimited Continuations . In Olivier Danvy & Ugo de’Liguoro, editors:
Proceedings of the Workshop onContinuations, WoC 2016, London, UK, April 12th 2015 , EPTCS
A Survey of Graphical Languages for Monoidal Categories , pp. 289–355. Springer BerlinHeidelberg, Berlin, Heidelberg, doi:10.1007/978-3-642-12821-9 4.[31] Andrew K. Wright & Matthias Felleisen (1994):