Refocusing (semantics)

Uses your system voice; voice and rate in settings.

Snapshot

≈ 10 min read

Names in other languages

No names in other languages are held for this entry yet.

Article bodies are English and are not machine-translated. A name in another language is not a translation of the article.

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 # 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 # 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.…

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 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 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 p_0 is first decomposed into the context C_0 and a potential redex \mathit{pr}_0 , \mathit{pr}_0 is contracted into the contractum c_0 , C_0 is then recomposed around c_0 and then decomposed into the context C_1 and a potential redex \mathit{pr}_1 , 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. type operator = Add | Quo;; type expression = Lit of int | Opr of expression * operator * expression;; So 1 + 10 is parsed as Opr (Lit 1, Add, Lit 10) and 11 / 2 is parsed as Opr (Lit 11, Quo, Lit 2) . type value = Int of int;; let expression_of_value (v : value) : expression = match v with Int n -> Lit n;; 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: type potential_redex = PR of value * operator * value;; type contractum_or_error = Contractum of expression | Error of string;; let contract (pr : potential_redex) : contractum_or_error = match pr with PR (Int n1, Add, Int n2) -> Contractum (Lit (n1 + n2)) | PR (Int n1, Quo, Int n2) -> if n2 = 0 then Error (string_of_int n1 ^ " / 0") else Contractum (Lit (n1 / n2));; 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 Opr (Opr (Lit 1, Add, Lit 10), Add, Lit 100) , i.e., (1+10)+100 , reduces to Opr (Lit 11, Add, Lit 100) , i.e., 11+100 , the expression Opr (Lit 11, Quo, Lit 2) , i.e., 11 / 2 , reduces to Lit 5 , i.e., 5 since 11 = 5 \cdot 2 + 1 , and the expression Opr (Opr (Lit 1, Quo, Lit 0), Add, Lit 100) , i.e., (1/0)+100 , reduces to Error "1 / 0" . 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: let rec reduce_d (e : expression) : value_or_expression_or_stuck = match e with Lit n -> Value (Int n) | Opr (e1, opr, e2) -> match reduce_d e1 with Value v1 -> (match reduce_d e2 with Value v2 -> (match contract (PR (v1, opr, v2)) with Contractum e -> Expression e | Error s -> Stuck s) | Expression e2' -> Expression (Opr (expression_of_value v1, opr, e2')) | Stuck s -> Stuck s) | Expression e1' -> Expression (Opr (e1', opr, e2)) | Stuck s -> Stuck s;; In words: a literal reduces to a value; if the expression e1 is stuck, then so is the expression Opr (e1, opr, e2) , for any expression e2 ; if the expression e1 reduces to an expression e1' , then for any expression e2 , Opr (e1, opr, e2) reduces to Opr (e1', opr, e2) ; if the expression e1 reduces to a value v1 , then if the expression e2 is stuck, then so is the expression Opr (e1, opr, e2) ; if the expression e2 reduces to an expression e2' , then Opr (e1, opr, e2) reduces to Opr (e1, opr, e2') ; if the expression e2 reduces to a value v2 , then Opr (e1, opr, e2) is a potential redex: if this potential redex is an actual one, then contracting it yields an expression; Opr (e1, opr, e2) reduces to this expression; if this potential redex is not an actual one, then Opr (e1, opr, e2) is stuck. Evaluation is achieved by iterated reduction. It yields either a value or an error message: type result = Normal_form of value | Wrong of string;; let rec normalize_d (e : expression) : result = match reduce_d e with Value v -> Normal_form v | Expression e' -> normalize_d e' | Stuck s -> Wrong s;; 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 constructing the context of the redex, contracting this redex, and recomposing the context around the contractum to yield the reduct: (1 - (5 + 5)) - (2 - 20) \ [(1 - (5 + 5)) - (2 - 20)] | explicit [[1 - (5 + 5)] - (2 - 20)] | 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 value_or_expression_or_stuck -> 'a to type value_or_expression_or_stuck -> value_or_expression_or_stuck , 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: type value_or_decomposition_cc = Val_cc of value | Dec_cc of potential_redex * (value -> value_or_decomposition_cc) * (expression -> expression);; let rec decompose_expression_cc (e : expression) (kd : value -> value_or_decomposition_cc) (kr : expression -> expression) : value_or_decomposition_cc = match e with Lit n -> kd (Int n) | Opr (e1, opr, e2) -> decompose_expression_cc e1 (fun v1 -> decompose_expression_cc e2 (fun v2 -> Dec_cc (PR (v1, opr, v2), kd, kr)) (fun e2' -> kr (Opr (expression_of_value v1, opr, e2')))) (fun e1' -> kr (Opr (e1', opr, e2)));; let decompose_cc (e : expression) : value_or_decomposition_cc = decompose_expression_cc e (fun v -> Val_cc v) (fun e' -> e');; let rec iterate_cc_rb (vod : value_or_decomposition_cc) : result = match vod with Val_cc v -> Normal_form v | Dec_cc (pr, kd, kr) -> (match contract pr with Contractum e -> iterate_cc_rb (decompose_cc (kr e)) | Error s -> (*^^^^^^^^^^^^^^^^^*) Wrong s);; let normalize_cc_rb (e : expression) : result = iterate_cc_rb (decompose_cc e);; 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. let rec iterate_cc_rf (vod : value_or_decomposition_cc) : result = match vod with Val_cc v -> Normal_form v | Dec_cc (pr, kd, kr) -> (match contract pr with Contractum e -> iterate_cc_rf (decompose_expression_cc e kd kr) | Error s -> (*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*) Wrong s);; let normalize_cc_rf (e : expression) : result = iterate_cc_rf (decompose_cc e);; 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 Rocq Proof Assistant. ==Correctness== Danvy and Nielsen stated conditions for refocusing and proved them informally. Sieczkowski, Biernacka, and Biernacki formalized refocusing using the Rocq Proof Assistant. Bach Poulsen proved the correctness of refocusing for XSOS using rule induction. Biernacka, Charatonik, and Zielińska generalized refocusing using the Rocq 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.

Text derived from https://en.wikipedia.org/w/index.php?oldid=1344425567 under CC BY-SA 4.0; modifications have been made.