Local Reasoning for Robust Observational Equivalence

07/02/2019
by   Dan R. Ghica, et al.
0

We propose a new core calculus for programming languages with effects, interpreted using a hypergraph-rewriting abstract machine inspired by the Geometry of Interaction. The intrinsic calculus syntax and semantics only deal with the basic structural aspects of programming languages: variable binding, name binding, and thunking. Everything else, including features which are commonly thought of as intrinsic, such as arithmetic or function abstraction and application, must be provided as extrinsic operations, with associated rewrite rules. The graph representation yields natural concepts of locality and robustness for equational properties and reduction rules, which enable a novel flexible and powerful reasoning methodology about (type-free) languages with effects. We illustrate and motivate the technique with challenging examples from the literature.

READ FULL TEXT VIEW PDF

Authors

page 1

page 2

page 3

page 4

10/25/2019

A Calculus for Language Transformations

In this paper we propose a calculus for expressing algorithms for progra...
02/04/2021

Operational Semantics with Hierarchical Abstract Syntax Graphs

This is a motivating tutorial introduction to a semantic analysis of pro...
12/25/2018

Induction, Coinduction, and Fixed Points: A Concise Comparative Survey (and Tutorial)

In this survey paper (which hitherto is an ongoing work-in-progress) we ...
10/07/2021

Toward a Theory of Programming Language and Reasoning Assistant Design: Minimizing Cognitive Load

Current approaches to making programming languages and reasoning assista...
06/13/2020

Pure Pattern Calculus à la de Bruijn

It is well-known in the field of programming languages that dealing with...
01/29/2020

A Type and Scope Safe Universe of Syntaxes with Binding: Their Semantics and Proofs

Almost every programming language's syntax includes a notion of binder a...
06/17/2015

Pragmatic Side Effects

In the quest to give a formal compositional semantics to natural languag...
This week in AI

Get the week's most popular data science and artificial intelligence research sent straight to your inbox every Saturday.

1 Introduction

1.1 Context and motivation

Program equivalence is an old central question in the study of programming languages. Establishing whether two program fragments are equivalent has immediate consequences regarding compiler optimisation and correctness, program verification and validation, and other key applications. The standard formal definition of the concept is that of observational equivalence [morris1969lambda]. Two executable programs are observationally equivalent if they have the same input-output behaviour. On terms (program fragments) observational equivalence is the smallest congruence induced by using executable programs as contexts, a definition which makes direct reasoning difficult.

The mathematical challenge of observational equivalence is two-fold. On the one hand, quantifying over all contexts is unwieldy, which led to the development of indirect methods. As an extremal case, denotational semantics provides a model-theoretic route to proving program equivalence [scott1971toward], while the interplay of syntactic (operational) and denotational techniques led to the development of hybrid methods such as Kripke logical relations [statman1985logical] or trace semantics [jeffrey2005java]. On the other hand, program equivalences are notoriously fragile. Adding new semantic features to a language can break equivalences and, more significantly, can invalidate reasoning techniques wholesale. Increasing the expressiveness of a language goes hand in hand with increasing the discriminating power of contexts, and new techniques based on bisimulation have been devised to meet the challenge of increasingly realistic languages [koutavas2006small].

A methodological point that became increasingly clear is that the richness of features of modern programming languages demands a systematic study, ideally a classification, from the point of view of the consequences such features have on the equational properties of a language. The development of game semantics made it possible to give combinatorial, syntax-independent, orthogonal characterisations for entire classes of features such as state and control, e.g. the so-called abramsky1997game “cube”, or to replace the syntactic notion of context by an abstracted adversary [DBLP:journals/entcs/GhicaT12]. A classification [DBLP:journals/jfp/DreyerNB12] and characterisation [Dreyer10] of language features and their impact on reasoning has also been undertaken using logical relations.

1.2 Overview and contribution

In this paper we present a new approach to defining effects and proving observational equivalence based on a novel operational machinery inspired by the Geometry of Interaction (GoI) semantics of languages with effects [DBLP:conf/csl/HoshinoMH14, DBLP:conf/popl/MuroyaHH16]. In contrast with the usual definition of the semantic model as a token-passing abstract machine, we introduce a token-guided rewriting semantics of the underlying net [DBLP:conf/csl/MuroyaG17]. Unlike the original GoI machine, the graph-rewriting abstract machine can be shown to be efficient (in the sense of DBLP:conf/icfp/AccattoliBM14

) for common reduction strategies (by-value, by-need). In addition to the theoretical interest, the graph-rewriting abstract machine was also used to model exotic effects, inspired by machine learning applications, in which imperative computation can be transformed into pure computation by abstracting the state 

[DBLP:conf/lics/MuroyaCG18].

We revise and generalise the formulation of the graph-rewriting machine from graphs to so-called hypernets, which are hierarchical hypergraphs, in the sense that entire hypergraphs can be used as edge labels. The hypernet-rewriting abstract machine is used to interpret Spartan, a core calculus of three basic constructs: name binding, variable binding, and thunking. Everything else, including function-abstraction and function application, must be provided as an extrinsic operation, which comes with its own associated rewrite rules. The flow of control through the program is represented by a distinguished edge called a token (or a focus), which traverses the hypernet triggering reductions.

The main conceptual contribution of the paper arises from the hypernet formulation of the language semantics: the underlying hypergraph for a program provides a natural notion of locality, i.e. those nodes and edges which belong to a neighbourhood around a point of interest such as the token or a redex we want to reason about. Locality in turn gives rise to a notion of robustness of sub-graphs, which states that rewrites occurring elsewhere cannot interfere with it. From a reasoning perspective, locality and robustness are useful concepts, since they can be established via elementary case analysis comparing reduction rules pairwise. The key technical result is a characterisation theorem (Thm. LABEL:thm:MetaThm) which establishes, informally speaking, that robustness implies observational equivalence, a very handy conceptual tool111 Our concept of locality is not to be confused with memory locality, which concerns memory access during program execution. Our locality, together with robustness, captures impact that operations in a program make on other parts of the program during execution. Ours could be seen as a generalisation of memory locality, because memory access could be modelled as extrinsic features of Spartan..

We believe this is an important result because, for the first time, it goes beyond an enumerative approach to effects, to a syntax-independent characterisation of effects. There is no need to separate effects, for example, into state and control in order to reason about languages with effects. In fact there is no need to separate computations into pure and effectful. Only locality properties are important, in the sense that the formulation of a property involves a hypergraph neighbourhood rather than the whole graph, and that rewrite rules associated with various operations do not interfere with the property we aim to check. A large number of equivalences and effects encountered in programming languages will be seen to satisfy these conditions – but not all. Perhaps the simplest example of a reasonable non-local and non-robust effect is the function found in the OCaml Gc module, providing memory usage information amounting to measuring the size of the term under execution. In the presence of , which can be defined as an operation in our framework, almost all basic equivalences fail, for example the beta law (since the term grows smaller).

The hypernet semantics is a genuine abstract machine in the sense that it provides syntax-independent execution with a well-defined and reasonably realistic cost model (time and space). The effects are not merely encoded into a base metalanguage, but can be expressed directly as arbitrary actions on the machine state. If the aim is a language that enjoys a nice equational theory, then these equivalences should be robust relative to desirable equivalences. But arbitrary, possibly ill-behaved exotic effects are also definable if so desired.

Finally, another conceptual novelty introduced here is a refinement of the notion of contextual equivalence. The standard definition involves a quantification over all contexts, but in a language as flexible as Spartan contexts can be wild. Therefore it makes sense to restrict contexts so that they only have certain shapes, which correspond to the way contexts are formed in well-behaved languages. Moreover, equivalence is indexed by a preorder on natural numbers which allows the comparison of the number of evaluation steps. This means that if two terms are equivalent with respect to the greater-than-or-equal order then in-context substitution is guaranteed to reduce the number of evaluation steps. This can be used as a basis for qualitative and quantitative reasoning, as needed for example in compiler optimisation.

The structure of the paper is as follows. In Sec. 2 we present a simple calculus (Spartan) which intermediates syntactically between languages with effects and the focussed hypernet representation. Hypernet rewriting is overviewed in Sec. LABEL:sec:overview with enough technical detail to understand the examples in Sec. LABEL:sec:examples. The technical details of focussed hypernet rewriting are given in Sec. LABEL:sec:fgr, with the characterisation theorem and its proof presented in Sec. LABEL:sec:metatheorem-LABEL:sec:ProofMetaThm. Sec. LABEL:sec:appmetatheorem gives an application of the main characterisation theorem to proving observational equivalence. We conclude with a mention of related and future work.

An interpreter and visualiser of Spartan execution can be accessed online.222https://tnttodda.github.io/Spartan-Visualiser/

2 The Spartan calculus

The syntactic elements of Spartan are a set of variables , (ranged over by ), a set of atoms , (ranged over by ), and a set of operations (ranged over by ). The set of operations is partitioned into ; the partitions are called passive and active operations. We will usually denote a sequence of variables by , a sequence of atoms by , etc. These sequences may be empty, case in which we write . We denote the length of a sequence by and, if convenient we may treat the sequences as sets by writing , , etc.

Definition 2.1 (Spartan terms).

The terms of Spartan, typically ranged over by , are generated by the grammar:

The term formers are variables, names, name binding, variable binding, thunking and operations. Note that the sequences above may be empty. In particular, thunking may be applied without binding any particular variable (). In the formation of an operation term arguments are used eagerly and the arguments lazily (we also say they are deferred). The eager arguments are evaluated in the given order, whereas the evaluation of lazy arguments is deferred. The distinction between name-binding and variable-binding will be seen to play a crucial role in the management of sharing vs. copying during execution.

The calculus provides only the most basic infrastructure. All interesting computational content must be provided as particular operations. The following is a non-exhaustive list of such operations which may be added to the Spartan framework.

Some passive operations (constructors) that can be added to Spartan are numerical constants (), pairing (), empty tuple (), injections (), etc.

Some examples of active Spartan operations are successor (), addition (), conjunction (), conditionals (), recursion () etc.

Datatype destructors can also be added as active operations, for example projections (,

), pattern matching (

), etc.

Operations with multiple arguments can come in different flavours depending on order of evaluations and eagerness. For example disjunction can be left-to-right , right-to-left or short-cut . Pairs can be also evaluated left-to-right (as above), but also, right-to-left, or lazily.

Most strikingly, abstraction and application themselves can be presented as operations. Abstraction is simply a thunking of the function body: whereas application can be defined by-name or by-value, left-to-right or right-to-left: , , or .

Algebraic operations are operations of certain arity and equational properties, designed to characterise a class of computational effects [DBLP:journals/acs/PlotkinP03]. All examples of algebraic operations from loc. cit. can be presented as (active) Spartan operations. Non-deterministic choice

selects one of its deferred argument non-deterministically; equipping it with a probability

yields a probabilistic choice . Interactive input assigns an input value to bound variable , whereas interactive output produces the result of evaluating (eager) argument as an output value. Both operations continue with the deferred argument . State lookup and update take form and, respectively, . The difference from interactive I/O is that the first eager argument is evaluated to yield an atom, which serves as a location in a store. In their generic form, state operations and return a stored value and the empty pair, respectively, instead of continuing with a deferred argument. Finally, creation of a local state, in the generic form, is modelled by that stores evaluation result of to a fresh location (atom) and returns it.

Effect handlers are studied as a generalisation of exception handlers to algebraic effects in DBLP:journals/corr/PlotkinP13. In our setting, a handler that targets operations can be constructed by a passive operation tagged with the targets. It is natural to assume that targeted operations are never passive (e.g. lambda-abstraction, pairing operation, injection, and handlers themselves). These handler constructors are a (rare) example in which a deferred argument may bind more than one variables. A handler can be then used with the handling operation to evaluate with handler .

Control operators are similarly dealt with. The undelimited control operator can be defined as:

The delimited control operator of DBLP:conf/lfp/DanvyF90 can be defined as:

2.1 The Spartan type system

The type system is primarily used to distinguish thunks from eager terms and to ensure terms are well formed. However, this type system does not enforce any notion of runtime safety.

Eager terms have type and thunks have type for some , representing the number of bound variables that accompany the thunk. Note that is a valid type and that . Types are typically ranged over by . A sequence of types is denoted by an expression . This is empty if , and equal to a single type if , i.e. . The empty sequence is written as . We use syntactic sugar , and .

Each operation has an arity, given in the form of , indicating it takes eager arguments and thunks.

For a type and a term , judgements are written as , where all variables in and all atoms in are distinct. The rules are given in Fig. LABEL:fig:types, where . If is derivable, term is called a program.