The Worker/Wrapper Transformation

Similar documents
The Worker/Wrapper Transformation

Appendix for Calculating Correct Compilers

Calculating Correct Compilers

FUNCTIONAL PEARLS The countdown problem

HERMIT: An Equational Reasoning Model to Implementation Rewrite System for Haskell

EECS 700 Functional Programming

GADTs. Wouter Swierstra. Advanced functional programming - Lecture 7. Faculty of Science Information and Computing Sciences

Accurate Step Counting

Compiling Exceptions Correctly

Optimising Functional Programming Languages. Max Bolingbroke, Cambridge University CPRG Lectures 2010

Hutton, Graham and Bahr, Patrick (2016) Cutting out continuations. In: WadlerFest, April 2016, Edinburgh, Scotland.

Accurate Step Counting

Calculating an Exceptional Machine (Extended Version)

Induction in Coq. Nate Foster Spring 2018

Calculating an Exceptional Machine

Lambda calculus. Wouter Swierstra and Alejandro Serrano. Advanced functional programming - Lecture 6

Week 5 Tutorial Structural Induction

INTRODUCTION TO FUNCTIONAL PROGRAMMING

Continuation Passing Style. Continuation Passing Style

GADTs. Wouter Swierstra and Alejandro Serrano. Advanced functional programming - Lecture 7. [Faculty of Science Information and Computing Sciences]

Introduction to Functional Programming in Haskell 1 / 56

GADTs. Alejandro Serrano. AFP Summer School. [Faculty of Science Information and Computing Sciences]

Once Upon a Polymorphic Type

Ornaments in ML. Thomas Williams, Didier Rémy. April 18, Inria - Gallium

Advanced Type System Features Tom Schrijvers. Leuven Haskell User Group

Fall 2018 Lecture N

Lambda Calculus and Type Inference

Type families and data kinds

CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Dan Grossman Spring 2011

4.5 Pure Linear Functional Programming

1 Introduction. 3 Syntax

GADTs meet Subtyping

Lambda Calculus and Type Inference

COMP4161: Advanced Topics in Software Verification. fun. Gerwin Klein, June Andronick, Ramana Kumar S2/2016. data61.csiro.au

Lecture 5: Lazy Evaluation and Infinite Data Structures

Monads and all that I. Monads. John Hughes Chalmers University/Quviq AB

Combining Static and Dynamic Contract Checking for Curry

Work-in-progress: Verifying the Glasgow Haskell Compiler Core language

Verifying Program Invariants with Refinement Types

Generic Programming with Adjunctions

Lecture 6: Sequential Sorting

Basic Foundations of Isabelle/HOL

Haske k ll An introduction to Functional functional programming using Haskell Purely Lazy Example: QuickSort in Java Example: QuickSort in Haskell

Lecture #23: Conversion and Type Inference

Work-in-progress: "Verifying" the Glasgow Haskell Compiler Core language

Review. CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Let bindings (CBV) Adding Stuff. Booleans and Conditionals

Exercise 1 ( = 24 points)

Conversion vs. Subtyping. Lecture #23: Conversion and Type Inference. Integer Conversions. Conversions: Implicit vs. Explicit. Object x = "Hello";

CS 6110 S11 Lecture 25 Typed λ-calculus 6 April 2011

COMP80 Lambda Calculus Programming Languages Slides Courtesy of Prof. Sam Guyer Tufts University Computer Science History Big ideas Examples:

Program Calculus Calculational Programming

INF 212 ANALYSIS OF PROG. LANGS FUNCTION COMPOSITION. Instructors: Crista Lopes Copyright Instructors.

An introduction introduction to functional functional programming programming using usin Haskell

Structural polymorphism in Generic Haskell

Structures in Coq January 27th 2014

Types. Type checking. Why Do We Need Type Systems? Types and Operations. What is a type? Consensus

Fall 2013 Midterm Exam 10/22/13. This is a closed-book, closed-notes exam. Problem Points Score. Various definitions are provided in the exam.

College Functors, Applicatives

Static Analysis and Code Optimizations in Glasgow Haskell Compiler

Exercise 1 (2+2+2 points)

Writing code that I'm not smart enough to write. A funny thing happened at Lambda Jam

Theorem Proving Principles, Techniques, Applications Recursion

# true;; - : bool = true. # false;; - : bool = false 9/10/ // = {s (5, "hi", 3.2), c 4, a 1, b 5} 9/10/2017 4

CS 11 Haskell track: lecture 4. n This week: Monads!

Introduction to ML. Based on materials by Vitaly Shmatikov. General-purpose, non-c-like, non-oo language. Related languages: Haskell, Ocaml, F#,

Fall Recursion and induction. Stephen Brookes. Lecture 4

1.3. Conditional expressions To express case distinctions like

Booleans (aka Truth Values) Programming Languages and Compilers (CS 421) Booleans and Short-Circuit Evaluation. Tuples as Values.

Exercise 1 ( = 18 points)

Overview. Elements of Programming Languages. Evaluation order. Evaluation order

Liquidate your assets

Me and my research. Wouter Swierstra Vector Fabrics, 6/11/09

CS 11 Haskell track: lecture 1

CS 320: Concepts of Programming Languages

MPRI course 2-4 Functional programming languages Exercises

Combining Proofs and Programs in a Dependently Typed Language. Certification of High-level and Low-level Programs

What does my program mean?

λ calculus is inconsistent

Induction for Data Types

Lecture #13: Type Inference and Unification. Typing In the Language ML. Type Inference. Doing Type Inference

Programming Languages Lecture 14: Sum, Product, Recursive Types

Functional Programming. Overview. Topics. Definition n-th Fibonacci Number. Graph

A Library Writer s Guide to Shortcut Fusion

Sometimes it s good to be lazy

CS 457/557: Functional Languages

n n Try tutorial on front page to get started! n spring13/ n Stack Overflow!

Programming Up-to-Congruence, Again. WG 2.8 Estes Park

Recursion. What is Recursion? Simple Example. Repeatedly Reduce the Problem Into Smaller Problems to Solve the Big Problem

CIS 194: Homework 3. Due Wednesday, February 11, Interpreters. Meet SImPL

Verification in Coq. Prof. Clarkson Fall Today s music: Check Yo Self by Ice Cube

Advanced Functional Programming

Continuations and Continuation-Passing Style

Data types à la carte

Formal semantics of loosely typed languages. Joep Verkoelen Vincent Driessen

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 1/38

Towards Lean 4: Sebastian Ullrich 1, Leonardo de Moura 2.

3.4 Deduction and Evaluation: Tools Conditional-Equational Logic

School of Informatics, University of Edinburgh

Denotational Semantics. Domain Theory

CSCE 314 Programming Languages

Transcription:

The Worker/Wrapper Transformation Andy Gill 1 Graham Hutton 2 1 Galois, Inc. 2 University of Nottingham February 6, 2008 Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 1 / 31

The Worker/Wrapper Transformation? What is the Worker/Wrapper Transformation? The worker wrapper transformation is a rewriting technique which changes the type of a recursive computation Changing the type of a computation... is pervasive in functional programming useful in practice the essence of turning a specification into a implementation Worker/wrapper has been used inside the Glasgow Haskell compiler since its inception to rewriting functions that take lifted values (thunks) with unlifted, equivalent values. No direct proof of correctness; syntactical arguments given Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 2 / 31

This Talk Give example of traditional use of the Worker/Wrapper Transformation Deriving efficient last Formalize the Worker/Wrapper Transformation Using the rolling rule and basic functional programming Apply worker/wrapper recipe to some examples Revisit efficient last Deriving memoization Deriving the CPS translation Draw conclusions about general applicability Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 3 / 31

Example: Fetching the last element in a list in Haskell last [] = error "last: []" last [x] = x last (x:xs) = last xs Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 4 / 31

Example: Fetching the last element in a list in Haskell last [] = error "last: []" last [x] = x last (x:xs) = last xs If we desugar into Core Haskell, last looks like this last = λ v case v of [] error "last: []" (x:xs) case xs of [] x (_:_) last xs There are two case statements per recursive call Any recursive call of last will always contain at least one cons cell Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 4 / 31

Workers and Wrappers for last A possible alternative definition of last might be last :: [a] a last = λ v case v of [] error "last: []" (x:xs) last_work x xs last_work :: a [a] a last_work = λ x xs case xs of [] x (x :xs ) last_work x xs We have a wrapper last which acts as an impedance match between last and last_work. We have a worker last_work which does the recursive computation There now is only one case statement per recursive call This talk: Systematically deriving workers and wrappers like these. Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 5 / 31

Creating Workers and Wrappers for last last :: [a] -> a last = \ v -> case v of (x:xs) -> case xs of [] -> x (_:_) -> last xs Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 6 / 31

Creating Workers and Wrappers for last last :: [a] -> a last = last_work :: a -> [a] -> a last_work = \ x xs -> (\ v -> case v of (x:xs) -> case xs of [] -> x (_:_) -> last xs) (x:xs) Create the worker out of the body and an invented coercion to the target type Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 6 / 31

Creating Workers and Wrappers for last last :: [a] -> a last = \ v -> case v of (x:xs) -> last_work x xs last_work :: a -> [a] -> a last_work = \ x xs -> (\ v -> case v of (x:xs) -> case xs of [] -> x (_:_) -> last xs) (x:xs) Create the worker out of the body and an invented coercion to the target type Invent the wrapper which call the worker Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 6 / 31

Creating Workers and Wrappers for last last :: [a] -> a last = \ v -> case v of (x:xs) -> last_work x xs last_work :: a -> [a] -> a last_work = \ x xs -> (\ v -> case v of (x:xs) -> case xs of [] -> x (_:_) -> last xs) (x:xs) Create the worker out of the body and an invented coercion to the target type Invent the wrapper which call the worker These functions are mutually recursive Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 6 / 31

Inline Wrapper last :: [a] -> a last = \ v -> case v of (x:xs) -> last_work x xs last_work :: a -> [a] -> a last_work = \ x xs -> (\ v -> case v of (x:xs) -> case xs of [] -> x (_:_) -> last xs) (x:xs) We now inline last inside last_work Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 7 / 31

Inline Wrapper last :: [a] -> a last = \ v -> case v of (x:xs) -> last_work x xs last_work :: a -> [a] -> a last_work = \ x xs -> (\ v -> case v of (x:xs) -> case xs of [] -> x (_:_) -> (\ v -> case v of (x:xs) -> last_work x xs) xs) (x:xs) We now inline last inside last_work last_work is now trivially recursive. Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 7 / 31

β-reduce worker last :: [a] -> a last = \ v -> case v of (x:xs) -> last_work x xs last_work :: a -> [a] -> a last_work = \ x xs -> (\ v -> case v of (x:xs) -> case xs of [] -> x (_:_) -> (\ v -> case v of (x:xs) -> last_work x xs) xs) (x:xs) We now perform β-reduction Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 8 / 31

β-reduce worker last :: [a] -> a last = \ v -> case v of (x:xs) -> last_work x xs last_work :: a -> [a] -> a last_work = \ x xs -> case (x:xs) of (x:xs) -> case xs of [] -> x (_:_) -> (\ v -> case v of (x:xs) -> last_work x xs) xs We now perform β-reduction Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 8 / 31

β-reduce worker last :: [a] -> a last = \ v -> case v of (x:xs) -> last_work x xs last_work :: a -> [a] -> a last_work = \ x xs -> case (x:xs) of (x:xs) -> case xs of [] -> x (_:_) -> (\ v -> case v of (x:xs) -> last_work x xs) xs We now perform β-reduction Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 8 / 31

β-reduce worker last :: [a] -> a last = \ v -> case v of (x:xs) -> last_work x xs last_work :: a -> [a] -> a last_work = \ x xs -> case (x:xs) of (x:xs) -> case xs of [] -> x (_:_) -> case xs of (x:xs) -> last_work x xs We now perform β-reduction Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 8 / 31

Case rules last :: [a] -> a last = \ v -> case v of (x:xs) -> last_work x xs last_work :: a -> [a] -> a last_work = \ x xs -> case (x:xs) of (x:xs) -> case xs of [] -> x (_:_) -> case xs of (x:xs) -> last_work x xs We have two instances of case on the same value Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 9 / 31

Case rules last :: [a] -> a last = \ v -> case v of (x:xs) -> last_work x xs last_work :: a -> [a] -> a last_work = \ x xs -> case (x:xs) of (x:xs) -> case xs of [] -> x (x:xs) -> last_work x xs We have two instances of case on the same value We can merge these case, removing redundant branches Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 9 / 31

Case of known constructor last :: [a] -> a last = \ v -> case v of (x:xs) -> last_work x xs last_work :: a -> [a] -> a last_work = \ x xs -> case (x:xs) of (x:xs) -> case xs of [] -> x (x:xs) -> last_work x xs We have case of a known constructor, cons. Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 10 / 31

Case of known constructor last :: [a] -> a last = \ v -> case v of (x:xs) -> last_work x xs last_work :: a -> [a] -> a last_work = \ x xs -> case xs of [] -> x (x:xs) -> last_work x xs We have case of a known constructor, cons. Being careful about naming, can remove the case We have reached our efficient implementation Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 10 / 31

Case of known constructor last :: [a] -> a last = \ v -> case v of (x:xs) -> last_work x xs last_work :: a -> [a] -> a last_work = \ x xs -> case xs of [] -> x (x:xs) -> last_work x xs We have case of a known constructor, cons. Being careful about naming, can remove the case We have reached our efficient implementation Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 10 / 31

The Informal Worker Wrapper Methodology From a recursive function, construct two new functions Wrapper Replacing the original function Coerces call to Worker Worker Performs main computation Syntactically contains the body of the original function Coerces call from Wrapper The initial worker and wrapper are mutually recursive We then inline the wrapper inside the worker, and simplify We end up with An efficient recursive worker An impedance matching non-recursive wrapper Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 11 / 31

Questions about the Worker/Wrapper Transformation Is the technique actually correct? How can this be proved? Under what conditions does it hold? How should it be used in practice? What kind of applications is it suitable for? Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 12 / 31

wrap and unwrap last :: [a] a Recursion Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 13 / 31

wrap and unwrap unwrap last :: [a] a work :: a [a] a wrap Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 13 / 31

wrap and unwrap last :: [a] a work :: a [a] a Recursion wrap Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 13 / 31

wrap and unwrap in General last :: A Recursion Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 14 / 31

wrap and unwrap in General unwrap last :: A work :: B wrap Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 14 / 31

wrap and unwrap in General last :: A work :: B Recursion wrap Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 14 / 31

Key wrap and unwrap Diagram unwrap last :: A work :: B wrap Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 15 / 31

Prerequisites comp :: A comp = fix body for some body :: A A wrap :: B A is a coercion from type B to A unwrap :: A B is a coercion from type A to B wrap unwrap = id A (basic worker/wrapper assumption) Worker/Wrapper Theorem If the above prerequisites hold, then comp = fix body can be rewritten as comp = wrap work where work :: B is defined by work = fix (unwrap body wrap) Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 16 / 31

The rolling rule fix(f.g) = f (fix(g.f )) Intuitively correct because both sides expand into f (g(f (g(f (g(...)))))) Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 17 / 31

Proof of Worker/Wrapper Theorem comp = { applyingcomp } fix body = { id is the identity for } fix (id body) = { assuming wrap unwrap = id } fix (wrap unwrap body) = { rolling rule } wrap (fix (unwrap body wrap)) = { define work = fix (unwrap body wrap) } wrap work Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 18 / 31

The worker/wrapper assumptions Key step of proof fix (id body) = { assuming wrap unwrap = id } fix (wrap unwrap body) We can actually use any of three different assumptions here wrap unwrap = id (basic assumption) wrap unwrap body = body (body assumption) fix (wrap unwrap body) = fix body (fix-point assumption) Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 19 / 31

Creating Workers and Wrappers for last unwrap last :: [a] a work :: a [a] a wrap wrap fn = \ xs -> case xs of (x:xs) -> fn x xs unwrap fn = \ x xs -> fn (x:xs) last = fix body body last = \ v -> case v of (x:[]) -> x (x:xs) -> last xs Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 20 / 31

Testing the basic worker/wrapper assumption wrap. unwrap = { apply wrap, unwrap and } \ fn -> (\ xs -> case xs of (x:xs) -> (\ x xs -> fn (x:xs)) x xs) = { β-reduction } \ fn -> (\ xs -> case xs of (x:xs) -> fn (x:xs)) Clearly not equal to id :: ([a] a) ([a] a) Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 21 / 31

Testing the body worker/wrapper assumption wrap. unwrap. body = { apply wrap, unwrap and } (\ fn -> (\ xs -> case xs of (x:xs) -> (\ x xs -> fn (x:xs)) x xs)) (\ last v -> case v of (x:[]) -> x (x:xs) -> last xs) Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 22 / 31

Testing the body worker/wrapper assumption wrap. unwrap. body = { apply wrap, unwrap and } = { β-reductions } (\ fn -> (\ xs -> case xs of (x:xs) -> case (x:xs) of (x:[]) -> x (x:xs) -> fn xs)) Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 22 / 31

Testing the body worker/wrapper assumption wrap. unwrap. body = { apply wrap, unwrap and } = { β-reductions } = { case of known constructors } (\ fn -> (\ xs -> case xs of (x:xs) -> case xs of [] -> x xs -> fn xs)) Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 22 / 31

Testing the body worker/wrapper assumption wrap. unwrap. body = { apply wrap, unwrap and } = { β-reductions } = { case of known constructors } = { common up case } (\ fn -> (\ xs -> case xs of (x:[]) -> x (x:xs) -> fn xs)) Which equals body. QED. Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 22 / 31

Applying the Worker/Wrapper Transformation last :: [a] -> a last = wrap work work :: a -> [a] -> a work = fix (unwrap. body. wrap) Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 23 / 31

Simplifing work last :: [a] -> a last xs = case xs of (x:xs) -> work x xs work :: a -> [a] -> a work = fix ( (\ fn x xs -> fn (x:xs)). (\ last v -> case v of (x:[]) -> x (x:xs) -> last xs). (\ fn xs -> case xs of (x:xs) -> fn x xs) ) Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 24 / 31

Simplifing work last :: [a] -> a last xs = case xs of (x:xs) -> work x xs work :: a -> [a] -> a work = fix ( \ fn x xs -> case (x:xs) of (x:[]) -> x (x:xs) -> case xs of (x:xs) -> fn x xs ) Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 24 / 31

Simplifing work last :: [a] -> a last xs = case xs of (x:xs) -> work x xs work :: a -> [a] -> a work = fix ( \ fn x xs -> case xs of [] -> x xs -> case xs of (x:xs) -> fn x xs ) Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 24 / 31

Simplifing work last :: [a] -> a last xs = case xs of (x:xs) -> work x xs work :: a -> [a] -> a work = fix ( \ fn x xs -> case xs of [] -> x (x:xs) -> fn x xs ) Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 24 / 31

Simplifing work last :: [a] -> a last xs = case xs of (x:xs) -> work x xs work :: a -> [a] -> a work x xs = case xs of [] -> x (x:xs) -> work x xs Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 24 / 31

The Worker/Wrapper Recipe Recipe Express the computation as a least fixed point; Choose the desired new type for the computation; Define conversions between the original and new types; Check they satisfy one of the worker/wrapper assumptions; Apply the worker/wrapper transformation; Simplify the resulting definitions. We simplify to remove the overhead of the wrap and unwrap coercions, often using fusion, including worker/wrapper fusion property. The Worker/Wrapper Fusion Property If wrap unwrap = id, then (unwrap wrap) work = work Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 25 / 31

Deriving Memoisation fib :: Int Int fib n = if n < 2 then 1 else fib (n 1) + fib (n 2) fib :: Nat Nat unwrap work :: [Nat] wrap :: [Nat] (Nat Nat) wrap xs ix = xs!! ix wrap unwrap :: (Nat Nat) [Nat] unwrap f = map f [0..] After proving that wrap unwrap = id, and applying rewrites, we reach fib :: Nat Nat fib n = work!! n work = map f [0..] where f = if n < 2 then 1 else work!! (n 1) + work!! (n 2) Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 26 / 31

Deriving a CPS version of a small evaluator data Expr = Val Int Add Expr Expr Throw Catch Expr Expr eval :: Expr Maybe Int eval (Val n) = Just n eval (Add x y) = case eval x of Nothing Nothing Just n case eval y of Nothing Nothing Just m Just (n+m) eval (Throw) = Nothing eval (Catch x y) = case eval x of Nothing eval y Just n Just n Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 27 / 31

CPS wrap and unwrap for our small evaluator unwrap eval :: Expr Maybe Int work :: Expr (Int Maybe Int) Maybe Int Maybe Int wrap unwrap :: (Expr Maybe Int) (Expr (Int Maybe Int) Maybe Int Maybe Int) unwrap g e s f = case (g e) of Nothing f Just n s n wrap :: (Expr (Int Maybe Int) Maybe Int Maybe Int) (Expr Maybe Int) wrap g e = g e Just Nothing Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 28 / 31

Result of deriving a CPS version of a small evaluator work :: Expr (Int Maybe Int) Maybe Int Maybe Int work (Val n) s f = s n work (Add x y) s f = work x (λn work y (λm s (n+m)) f) f work (Throw) s f = f work (Catch x y) s f = work x s (work y s f) Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 29 / 31

Conclusions Worker/wrapper is a general and systematic approach to transforming a computation of one type into an equivalent computation of another type It is straightforward to understand and apply, requiring only basic equational reasoning techniques, and often avoiding the need for induction. It allows many seemingly unrelated optimization techniques to be captured inside a single unified framework Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 30 / 31

Further Work Monadic and Effectful Constructions Mechanization Implement inside the Haskell Equational Reasoning Assistant Consider other patterns of recursion Andy Gill, Graham Hutton The Worker/Wrapper Transformation February 6, 2008 31 / 31