313 research outputs found
Mechanized semantics
The goal of this lecture is to show how modern theorem provers---in this
case, the Coq proof assistant---can be used to mechanize the specification of
programming languages and their semantics, and to reason over individual
programs and over generic program transformations, as typically found in
compilers. The topics covered include: operational semantics (small-step,
big-step, definitional interpreters); a simple form of denotational semantics;
axiomatic semantics and Hoare logic; generation of verification conditions,
with application to program proof; compilation to virtual machine code and its
proof of correctness; an example of an optimizing program transformation (dead
code elimination) and its proof of correctness
Introduction to the Literature on Semantics
An introduction to the literature on semantics. Included are pointers to the literature on axiomatic semantics, denotational semantics, operational semantics, and type theory
A Transformation-Based Foundation for Semantics-Directed Code Generation
Interpreters and compilers are two different ways of implementing
programming languages. An interpreter directly executes its program
input. It is a concise definition of the semantics of a programming
language and is easily implemented. A compiler translates its program
input into another language. It is more difficult to construct, but
the code that it generates runs faster than interpreted code.
In this dissertation, we propose a transformation-based foundation for
deriving compilers from semantic specifications in the form of four
rules. These rules give apriori advice for staging, and allow
explicit compiler derivation that would be less succinct with partial
evaluation. When applied, these rules turn an interpreter that
directly executes its program input into a compiler that emits the
code that the interpreter would have executed.
We formalize the language syntax and semantics to be used for the
interpreter and the compiler, and also specify a notion of equality.
It is then possible to precisely state the transformation rules and to
prove both local and global correctness theorems. And although the
transformation rules were developed so as to apply to an interpreter
written in a denotational style, we consider how to modify
non-denotational interpreters so that the rules apply. Finally, we
illustrate these ideas by considering a larger example: a Prolog
implementation
Forms of Semantic Specification
The way to specify a programming language has been a topic of heated debate for some decades and at present there is no consensus on how this is best done. Real languages are almost always specified informally; nevertheless, precision is often enough lacking that more formal approaches could benefit both programmers and language implementors. My purpose is to look at a few of these formal approaches in hope of establishing some distinctions or at least stirring some discussion
A Simple Solution to Type Specialization
Partial evaluation specializes terms, but traditionally thisspecialization does not apply to the type of these terms. As a result, specializing, e.g., an interpreter written in a typed language, which requires a "universal" type to encode expressible values, yields residual programs with type tags all over. Neil Jones has stated that getting rid of these type tags was an open problem, despite possible solutions such as Torben Mogensen's "constructor specialization." To solve this problem, John Hughes has proposed a new paradigm for partial evaluation, "Type Specialization," based on type inference instead of being based on symbolic interpretation. Type Specialization is very elegant in principle but it also appears non-trivial in practice. Stating the problem in terms of types instead of in terms of type encodings suggests a very simple type-directed solution, namely, to use a projection from the universal type to the specific type of the residual program. Standard partial evaluation then yields a residual programwithout type tags, simply and efficiently
Programming with Algebraic Effects and Handlers
Eff is a programming language based on the algebraic approach to
computational effects, in which effects are viewed as algebraic operations and
effect handlers as homomorphisms from free algebras. Eff supports first-class
effects and handlers through which we may easily define new computational
effects, seamlessly combine existing ones, and handle them in novel ways. We
give a denotational semantics of eff and discuss a prototype implementation
based on it. Through examples we demonstrate how the standard effects are
treated in eff, and how eff supports programming techniques that use various
forms of delimited continuations, such as backtracking, breadth-first search,
selection functionals, cooperative multi-threading, and others
Interaction Trees: Representing Recursive and Impure Programs in Coq
"Interaction trees" (ITrees) are a general-purpose data structure for
representing the behaviors of recursive programs that interact with their
environments. A coinductive variant of "free monads," ITrees are built out of
uninterpreted events and their continuations. They support compositional
construction of interpreters from "event handlers", which give meaning to
events by defining their semantics as monadic actions. ITrees are expressive
enough to represent impure and potentially nonterminating, mutually recursive
computations, while admitting a rich equational theory of equivalence up to
weak bisimulation. In contrast to other approaches such as relationally
specified operational semantics, ITrees are executable via code extraction,
making them suitable for debugging, testing, and implementing software
artifacts that are amenable to formal verification.
We have implemented ITrees and their associated theory as a Coq library,
mechanizing classic domain- and category-theoretic results about program
semantics, iteration, monadic structures, and equational reasoning. Although
the internals of the library rely heavily on coinductive proofs, the interface
hides these details so that clients can use and reason about ITrees without
explicit use of Coq's coinduction tactics.
To showcase the utility of our theory, we prove the termination-sensitive
correctness of a compiler from a simple imperative source language to an
assembly-like target whose meanings are given in an ITree-based denotational
semantics. Unlike previous results using operational techniques, our
bisimulation proof follows straightforwardly by structural induction and
elementary rewriting via an equational theory of combinators for control-flow
graphs.Comment: 28 pages, 4 pages references, published at POPL 202
- …