Refocusing (semantics)

In computer science, refocusing is a program transformation used to implement a reduction semantics—i.e., a small-step operational semantics with an explicit representation of the reduction context—more efficiently. It is a step towards implementing a deterministic semantics as a deterministic abstract machine.

A small-step operational semantics defines the meaning of a given program $$p_0$$ as a sequence of one-step reductions that starts with $$p_0$$ and continues with a sequence of reducts $$p_i$$, where $$i > 0$$:

$$p_0 \rightarrow p_1 \rightarrow p_2 \rightarrow \cdots$$

A one-step reduction from $$p_n$$ to $$p_{n+1}$$ is achieved by
 * 1) locating the smallest potentially reducible term (potential redex) using a given reduction strategy, if this potential redex exists in $$p_n$$ (otherwise $$p_n$$ is irreducible); and
 * 2) contracting this potential redex using given contraction rules if it is an actual one (otherwise $$p_n$$ is stuck).

A reduction semantics is a small-step operational semantics with an explicit representation of the context of each potential redex.

Writing $$C$$ for such context, the sequence of one-step reductions above reads:

$$p_0 = C_0[\mathit{pr}_0] \rightarrow C_0[c_0] = C_1[\mathit{pr}_1] \rightarrow C_1[c_1] = C_2[\mathit{pr}_2] \rightarrow C_2[c_2] \rightarrow \cdots$$

where
 * 1) $$p_0$$ is first decomposed into the context $$C_0$$ and a potential redex $$\mathit{pr}_0$$,
 * 2) $$\mathit{pr}_0$$ is contracted into the contractum $$c_0$$,
 * 3) $$C_0$$ is then recomposed around $$c_0$$ and then decomposed into the context $$C_1$$ and a potential redex $$\mathit{pr}_1$$,
 * 4) etc.

This succession of decompositions, contractions, and recomposition is depicted as follows:

contract              contract               contract o->o          o->o           o->o /           \         /            \         /            \          /    recompose \       /    recompose \       /    recompose \ /               \     /                \     /                \      / decompose        \   / decompose        \   / decompose        \ /                   \ /                    \ /                    \  o->o->o->o reduce                reduce                 reduce

Refocusing is a deforestation of the successive reducts:

contract   refocus    contract    refocus    contract o->o-->o->o-->o->o-- /           \         /            \         /            \          /    recompose \       /    recompose \       /    recompose \ /               \     /                \     /                \      / decompose        \   / decompose        \   / decompose        \ /                   \ /                    \ /                    \  o                      o                      o                      o

After the initial decomposition, the succession of contractions and refocusings has the structure of a deterministic abstract machine.

Background
The semantics of a programming language defines the meaning of the programs written in this programming language. Plotkin's Structural Operational Semantics is a small-step semantics where the meaning of a program is defined step by step and where each step is an elementary operation that is carried out with contraction rules.

Example
Consider the following deterministic language of arithmetic expressions over integers with additions and quotients, in the manner of Hutton's razor.

In OCaml:

So $$1 + 10$$ is parsed as and $$11 / 2$$ is parsed as.

The smallest potentially reducible expressions (potential redexes) are operations over values, and they are carried out with a contraction function that maps an actual redex to an expression and otherwise yields an error message:

The addition of two integers is an actual redex, and so is the quotient of an integer and a nonzero integer. So for example, the expression , i.e., $$(1+10)+100$$, reduces to , i.e., $$11+100$$, the expression , i.e., $$11 / 2$$, reduces to , i.e., $$5$$ since $$11 = 5 \cdot 2 + 1$$, and the expression , i.e., $$(1/0)+100$$, reduces to.

Say that the reduction strategy is leftmost-innermost (i.e., depth first and left to right), as captured by the following congruence rules:

e1 -> e1' ---    Opr (e1, opr, e2) -> Opr (e1', opr, e2) e2 -> e2' --- Opr (Lit n1, opr, e2) -> Opr (Lit n1, opr, e2')

The following one-step reduction function implements this strategy:

In words:


 * a literal reduces to a value;
 * if the expression  is stuck, then so is the expression , for any expression  ;
 * if the expression  reduces to an expression , then for any expression  ,   reduces to  ;
 * if the expression  reduces to a value , then
 * if the expression  is stuck, then so is the expression  ;
 * if the expression  reduces to an expression , then   reduces to  ;
 * if the expression  reduces to a value , then   is a potential redex:
 * if this potential redex is an actual one, then contracting it yields an expression;  reduces to this expression;
 * if this potential redex is not an actual one, then  is stuck.

Evaluation is achieved by iterated reduction. It yields either a value or an error message:

This one-step reduction function is structurally recursive. It implements a Structural Operational Semantics for this minimalistic language of arithmetic expressions with errors.

For example, the reduction function implicitly constructs the following proof tree to carry out the reduction step $$ (1 - (5 + 5)) - (2 - 20) \rightarrow (1 - 10) - (2 - 20) $$:

5 + 5 -> 10              -              1 - (5 + 5) -> 1 - 10 --- (1 - (5 + 5)) - (2 - 20) -> (1 - 10) - (2 - 20)

Reformatting this proof tree to emphasize the implicit decomposition yields:

-->               ^                 contraction                         | |        -               |                |         5 + 5              ->      10               |    implicit    |    --               | implicit decomposition |   1 - (5 + 5)             ->  1 - 10               | recomposition |  ---   |                |   (1 - (5 + 5)) - (2 - 20) -> (1 - 10) - (2 - 20)   v

A reduction semantics is a small-step operational semantics where the implicit context of a potential redex is made explicit. So one reduction step gives rise to
 * 1) constructing the context of the redex,
 * 2) contracting this redex, and
 * 3) recomposing the context around the contractum to yield the reduct:

(1 - (5 + 5)) - (2 - 20) \ [(1 - (5 + 5)) - (2 - 20)] | explicit decomposition [[1 - [5 + 5 - (2 - 20)] /                             contraction 1 - [ 10   - (2 - 20)] \ [[1 -   10   ] - (2 - 20)] | explicit [(1 -   10   ) - (2 - 20)] | recomposition  (1 -   10   ) - (2 - 20)  /

And pictorially, an arithmetic expression is evaluated in successive steps:

contract              contract               contract o->o          o->o           o->o /           \         /            \         /            \          /    recompose \       /    recompose \       /    recompose \ /               \     /                \     /                \      / decompose        \   / decompose        \   / decompose        \ /                   \ /                    \ /                    \  o->o->o->o reduce                reduce                 reduce

Transforming the one-step reduction function in Continuation-Passing Style, delimiting the continuation from type  to type  , and splitting this delimited continuation into two (one to continue the decomposition and one to recompose, using the type isomorphism between $$A + B \rightarrow C$$ and $$(A \rightarrow C) \times (B \rightarrow C)$$) makes it simple to implement the corresponding normalization function:

In the underlined code, the contractum is recomposed and the result is decomposed. This normalization function is said to be reduction-based because it enumerates all the reducts in the reduction sequence.

Refocusing
Extensionally, the refocusing thesis is that there is no need to reconstruct the next reduct in order to decompose it in the next reduction step. In other words, these intermediate reducts can be deforested.

Pictorially:

contract   refocus    contract    refocus    contract o->o-->o->o-->o->o-- /           \         /            \         /            \          /    recompose \       /    recompose \       /    recompose \ /               \     /                \     /                \      / decompose        \   / decompose        \   / decompose        \ /                   \ /                    \ /                    \  o                      o                      o                      o

Intensionally, the refocusing thesis is that this deforestation is achieved by continuing the decomposition over the contractum in the current context.

In the underlined code, the decomposition is continued. This normalization function is said to be reduction-free because it enumerates none of the reducts in the reduction sequence.

In practice, the two continuations are defunctionalized into traditional first-order, inside-out contexts, which yields an implementation of Felleisen and Hieb's reduction semantics, a small-step semantics that was designed independently of continuations and defunctionalization, but whose representation—as illustrated here—can be obtained by CPS-transforming and defunctionalizing the representation of a Structural Operational Semantics.

The construction sketched above is completely formalized using the Coq Proof Assistant.

Applications
Over the years, refocusing has been used for inter-deriving calculi and abstract machines. Besides the CEK Machine, the Krivine machine, and the SECD machine, examples also include the chemical abstract machine and abstract machines for JavaScript. Bach Poulsen and Mosses have also used refocusing for implementing Structural Operational Semantics and Modular Structural Operational Semantics.

More broadly, refocusing has been used for deriving type systems and implementations for coroutines, for going from type checking via reduction to type checking via evaluation, for deriving a classical call-by-need sequent calculus, for deriving interpretations of the gradually-typed lambda calculus, and for full reduction.

Correctness
Danvy and Nielsen stated conditions for refocusing and proved them informally. Sieczkowski, Biernacka, and Biernacki formalized refocusing using the Coq Proof Assistant. Bach Poulsen proved the correctness of refocusing for XSOS using rule induction. Biernacka, Charatonik, and Zielińska generalized refocusing using the Coq Proof Assistant. Using Agda, Swiestra proved the refocusing step as part of his formalization of the syntactic correspondence between the $$\lambda\widehat{\rho}$$ calculus with a normal-order reduction strategy and the Krivine machine. Also using Agda, Rozowski proved the refocusing step as part of his formalization of the syntactic correspondence between the $$\lambda\widehat{\rho}$$ calculus with an applicative-order reduction strategy and the CEK Machine.