+ All Categories
Home > Documents > Warm Fusion in Yicho

Warm Fusion in Yicho

Date post: 18-Nov-2023
Category:
Upload: independent
View: 0 times
Download: 0 times
Share this document with a friend
20
Warm Fusion in Yicho Tetsuo Yokoyama, Zhenjiang Hu,, Masato TakeichiDept. of Mathematical Informatics Graduate School of Information Science and Technology The University of Tokyo {tetsuo yokoyama,hu,takeichi}@mist.i.u-tokyo.ac.jp PRESTO 21, Japan Science and Technology Agency Abstract Mechanical Implementation of warm fusion by program transformation system Yicho is described. Yicho is a monadic combinator library implemented in Haskell using the mechanism of meta-programming exten- sion. Warm fusion is formalized as calculation rules that are straightforwardly programmed using Yicho with help of higher-order patterns which have more expressive power than the patterns in usual functional languages. The most advantage of our approach is concise representation of calculations; we reduce warm fusion code in Yicho into one tenth as long as in an existent approach using a program transformation system Stratego. Keywords. Yicho System, Warm Fusion, Program Transformation, Calculation, Automatic Program Gen- eration 1 Introduction Constructing programs from components, i.e., modules, is an important technique in designing large software. Dividing programs according to its functionality realizes localization of problems in a single module. Conse- quently, programs are maintained of ease. If each module is maintained as a versatile component, reusability is improved. The problem is, however, performance down due to unnecessary intermediate data structures passed between modules. Improvement of performance can be achieved if these intermediate data structures are removed by automatic analysis and automatic transformation. Deforestation, a well-known program transformation proposed by Wadler [Wad90], is a technique of elimi- nation of intermediate data structures. Descendent from it, Gill et al. [GLP93] proposes shortcut deforestation. Notably, shortcut deforestation consists of a single, simple, local transformation rule, and thus it eases the implementation [PTH01]. Though shortcut deforestation can successfully fuse a wide class of functions, its applicability is limited; the precondition of shortcut deforestation assumes the producer function to be ex- pressed in terms of build. This restriction is a bit relaxed by generalizing build into augment to handle list production functions generally [Gil96]. Nevertheless, because functions are usually written in recursive forms, these assumptions are unrealistic in practice. Warm fusion [LS95] is a preprocess for shortcut deforestation. It transforms recursive functions into func- tions in terms of build automatically. The technique has been implemented with program transformation system Stratego [JV00], which is based on term rewriting system. The implementation of warm fusion, how- ever, appears to be complex. There is another approach which derives the build form through type inference [Chi99, Chi00]. This approach is easier to implement and is able to transform more producers into the build form than warm fusion. But, implementation of this approach is still difficult. In this paper, we show the following new contributions. Firstly, we formalize warm fusion on lists in calculational form with a set of rules being suitable for implementation. The formalization is very concise due to expressive power of higher-order patterns. Secondly, we implement the warm fusion theory in Yicho. Calculation rules of warm fusion can be straightforwardly represented in Yicho. Yicho code is compiled by GHC (Glasgow Haskell Compiler) [GHC] and at compile time warm fusion is automatically applied. The intermediate data structures of the result code of warm fusion is removed by shortcut deforestation at the following phase of compilation. All codes in this paper have been tested on GHC 6.2.1. The rest of this paper is structured as follows. In Section 2, we present warm fusion problem and formalize warm fusion in calculational form. Readers interested in the implementation of warm fusion in Yicho are advised
Transcript

Warm Fusion in Yicho

Tetsuo Yokoyama†, Zhenjiang Hu†,‡, Masato Takeichi††Dept. of Mathematical Informatics

Graduate School of Information Science and TechnologyThe University of Tokyo

{tetsuo yokoyama,hu,takeichi}@mist.i.u-tokyo.ac.jp‡PRESTO 21, Japan Science and Technology Agency

Abstract

Mechanical Implementation of warm fusion by program transformation system Yicho is described. Yichois a monadic combinator library implemented in Haskell using the mechanism of meta-programming exten-sion. Warm fusion is formalized as calculation rules that are straightforwardly programmed using Yichowith help of higher-order patterns which have more expressive power than the patterns in usual functionallanguages. The most advantage of our approach is concise representation of calculations; we reduce warmfusion code in Yicho into one tenth as long as in an existent approach using a program transformationsystem Stratego.Keywords. Yicho System, Warm Fusion, Program Transformation, Calculation, Automatic Program Gen-eration

1 Introduction

Constructing programs from components, i.e., modules, is an important technique in designing large software.Dividing programs according to its functionality realizes localization of problems in a single module. Conse-quently, programs are maintained of ease. If each module is maintained as a versatile component, reusabilityis improved. The problem is, however, performance down due to unnecessary intermediate data structurespassed between modules. Improvement of performance can be achieved if these intermediate data structuresare removed by automatic analysis and automatic transformation.

Deforestation, a well-known program transformation proposed by Wadler [Wad90], is a technique of elimi-nation of intermediate data structures. Descendent from it, Gill et al. [GLP93] proposes shortcut deforestation.Notably, shortcut deforestation consists of a single, simple, local transformation rule, and thus it eases theimplementation [PTH01]. Though shortcut deforestation can successfully fuse a wide class of functions, itsapplicability is limited; the precondition of shortcut deforestation assumes the producer function to be ex-pressed in terms of build. This restriction is a bit relaxed by generalizing build into augment to handle listproduction functions generally [Gil96]. Nevertheless, because functions are usually written in recursive forms,these assumptions are unrealistic in practice.

Warm fusion [LS95] is a preprocess for shortcut deforestation. It transforms recursive functions into func-tions in terms of build automatically. The technique has been implemented with program transformationsystem Stratego [JV00], which is based on term rewriting system. The implementation of warm fusion, how-ever, appears to be complex.

There is another approach which derives the build form through type inference [Chi99, Chi00]. Thisapproach is easier to implement and is able to transform more producers into the build form than warmfusion. But, implementation of this approach is still difficult.

In this paper, we show the following new contributions. Firstly, we formalize warm fusion on lists incalculational form with a set of rules being suitable for implementation. The formalization is very concisedue to expressive power of higher-order patterns. Secondly, we implement the warm fusion theory in Yicho.Calculation rules of warm fusion can be straightforwardly represented in Yicho. Yicho code is compiled byGHC (Glasgow Haskell Compiler) [GHC] and at compile time warm fusion is automatically applied. Theintermediate data structures of the result code of warm fusion is removed by shortcut deforestation at thefollowing phase of compilation. All codes in this paper have been tested on GHC 6.2.1.

The rest of this paper is structured as follows. In Section 2, we present warm fusion problem and formalizewarm fusion in calculational form. Readers interested in the implementation of warm fusion in Yicho are advised

to skip this section. In Section 3, program calculation system Yicho is described. In Section 4, implementationof warm fusion in Yicho is described. Finally, we conclude and discuss related works and future works inSection 5.

2 Warm Fusion

In this section, we formalize warm fusion in calculational form. Throughout the paper we use Haskell nota-tion [Bir98].

Warm fusion is a technique to transform recursive programs into constructor-abstraction form (e.g. build).Consider, for example, the familiar map function, which applies a function to each element of a list.

map f [] = []map f (x : xs) = f x : map f xs

This function produces list data structure, which consists of two constructors (:) and []. To abstract theseconstructors, we introduce function build.

build g = g (:) []

Function g should use two arguments for constructors of the output list. The result of warm fusion of functionmap is

map f = λxs. build (λc n. foldr (c ◦ f) n xs)

Here, function foldr (⊕) e replaces constructors (:) and [] in a given list with (⊕) and e respectively.

foldr (⊕) e [] = e

foldr (⊕) e (x : xs) = x ⊕ foldr (⊕) e xs

Actually, warm fusion is a preprocess of well-known optimization technique shortcut deforestation, definedas follows1.

foldr k z (build g) = g k z

Instead of producing list by passing (:) and [] to g and then replacing list constructors (:) and [] with k andz respectively, we do not produce any list constructor but directly pass k and z to function g. In GHC, buildform and foldr form are prepared for all the functions in prelude (standard function library). A function ofcomputing summation of a given list is

sum = foldr (+) 0

At the compile time, shortcut deforestation rule is fired in the following way by term rewriting with simplestrategy.

sum (map f xs)= { Inline sum and map }

foldr (+) 0 (build (λc n. foldr (c ◦ f) n xs))= { Shortcut Deforestation }

foldr ((+) ◦ f) 0 xs

While the function composition sum◦map f is inefficient due to intermediate data structure passing from map

to sum, the result function does not have any intermediate data structure.If we could prepare all the functions in terms of foldr and build, this calculations would remove intermediate

data structures automatically. But this is out of question. Functional programmer usually describes programas recursive forms, since foldr form and build form are less natural than recursive forms. Therfore, the problemis how to derive foldr form and build form from a recursive form. There is an approach automatically derivingfoldr form [SF93]. Derivation of foldr form is easily achieved by promotion theorem. Therefore, the problem issettled down into derivation of build form from recursive function, say, warm fusion problem.

Most generally, any recursion can be trivially transformed into the build form. Given any function f , bothproducing and consuming lists, can be rewritten as

λxs. build (λc n. foldr c n (f (foldr (:) [] xs)))

without considering performance. Therefore, the difficulty of warm fusion is efficiency. The inefficiency isdue to intermediate data structure passing from f to foldr c n. If we can fuse foldr c n, f , and foldr (:) [],

1Strictly speaking, we need certain type restriction on g.

we may optimize the code. Though the general fusion problem is very difficult, if the right hand side of thecomposition is described in terms of foldr, they satisfy a number of calculational properties, one of which ispromotion lemma.

Lemma 1 (Promotion)

f e = e′

f (x ⊕ xs) = x ⊗ f xs

f ◦ foldr (⊕) e = foldr (⊗) e′

Promotion lemma gives the condition to fuse two functions. Function f is merged into function foldr and theresult is also foldr form. If (⊕) and e are (:) and [], this is merely the definition of inductive recursive functionon list. Then, if f is inductive recursive function and we can find (⊗) and e′ satisfying the above conditions,the warm fusion problem is settled down into the problem to fuse

foldr c n ◦ foldr (⊗) e′.

Promotion lemma is applicable to the composition. But, since the left function of function composition isalways function foldr c n, we can rely on the fact and define specific theorem. The theorem vary accordingto the form of the right foldr. We show the first-order case and show the second-order case in the followingsubsections.

2.1 First-order Warm Fusion

When the right foldr takes three arguments and is saturated, we can use first-order warm fusion theorem.Before stating and proving the theorem, we prepare the calculation lemma for fusing two foldr’s.

Lemma 2 (First-order Promotion of Two foldr’s)

foldr c′ n′ e = e′ c′ n′

foldr c′ n′ (x ⊕ xs) = (x ⊗ λc′ n′. foldr c′ n′ xs) c′ n′

foldr c n (foldr (⊕) e xs) = foldr (⊗) e′ xs c n

Proof. We prove by induction over xs. Base case:

lhs= foldr c′ n′ (foldr (⊕) e [])= { Definition of foldr }

foldr c′ n′ e

= { Precondition }

e′ c′ n′

= { Definition of foldr }

foldr (⊗) e′ [] c′ n′

= rhs

Inductive case:lhs= foldr c′ n′ (foldr (⊕) e (x : xs))= { Definition of foldr }

foldr c′ n′ (x ⊕ foldr (⊕) e xs)= { Precondition }

(x ⊗ λc′ n′. foldr c′ n′ (foldr (⊕) e xs)) c′ n′

= { Induction Hypothesis }

(x ⊗ λc′ n′. foldr (⊗) e′ xs c′ n′) c′ n′

= { η-contraction }

(x ⊗ foldr (⊗) e′ xs) c′ n′

= { Definition of foldr }

foldr (⊗) e′ (x : xs) c′ n′

= rhs

¤

Theorem 3 (First-order Warm Fusion)

f [] = e

f (x : xs) = x ⊕ f xs

foldr c′ n′ e = e′ c′ n′

foldr c′ n′ (x ⊕ xs) = (x ⊗ λc′ n′. foldr c′ n′ xs) c′ n′

f = λxs. build (λc n. foldr (⊗) e′ xs c n)

Proof. As seen before, any function f which takes a list and produces a list can be trivially transformed into

λxs. build (λc n. foldr c n (f (foldr (:) [] xs)))

Promotion lemma and precondition transforms it into

λxs. build (λc n. foldr c n (foldr (⊕) e xs))

By Lemma 2 and precondition, we finally obtain

f = λxs. build (λc n. foldr (⊗) e′ xs c n)

¤

Example 1 (map) Consider map f function. We attempt to apply Theorem 3. By the definition of map f ,we obtain

e = [](⊕) = ((:) ◦ f)

Using these operators, we calculatefoldr c′ n′ e

= { Definition of e }

foldr c′ n′ []= { Definition of foldr }

n′

foldr c′ n′ (x ⊕ xs)= { Definition of ⊕ }

foldr c′ n′ (f x : xs)= { Definition of foldr }

c′ (f x) (foldr c′ n′ xs)

Then, we try to match e′ c′ n′ with n′. By first-order matching, it fails. By second-order matching, it returns{e′ 7→ λc′ n′. n′}. In the following paper, we use matching for higher-order matching. For inductive case,matching

(x ⊗ λc′ n′. foldr c′ n′ xs) c′ n′

withc′ (f x) (foldr c′ n′ xs)

returns{(⊗) 7→ λx p c′ n′. c′ (f x) (p c′ n′)}

By Theorem 3 with these conditions, we obtain

λxs. build (foldr (λx p c′ n′. c′ (f x) (p c′ n′)) (λc′ n′. n′) xs)

The inner foldr can be simplified.

foldr (λx p c′ n′. c′ (f x) (p c′ n′)) (λc′ n′. n′) xs

= { η-expansion }

λc. foldr (λx p c′ n′. c′ (f x) (p c′ n′)) (λc′ n′. n′) xs c

= λc. ((λf. f c) ◦ foldr (λx p c′ n′. c′ (f x) (p c′ n′)) (λc′ n′. n′)) xs

= { Promotion }

λc. foldr (λx p c′. c (f x) (p c′)) id xs

= { η-expansion }

λc n. foldr (λx p c′. c (f x) (p c′)) id xs n

= λc n. ((λf. f n) ◦ foldr (λx p c′. c (f x) (p c′)) id) xs

= { Promotion }

λc n. foldr (c ◦ f) n xs

Finally, we obtain build-form of function map f

map f = λxs. build (λc n. foldr (c ◦ f) n xs)

It is noted that, while the build form of map f can be derived only by promotion lemma, by this examplewe examined Theorem 3 works and moreover in fact the result is as simple as that by promotion lemma only.

Example 2 (reverse) Consider a function to reverse a given list:

reverse [] = []reverse (x : xs) = reverse xs ++ [x]

where xs ++ ys = build (λc n. foldr c (foldr c n ys) xs)

Here, we assume (++ ) is already in build form. This calculation is in Appendix B. By definition of reverse, weobtain

e = []x ⊕ y = y ++ [x]

Using these operators, we calculate

foldr c′ n′ e

= { Definition of e }

foldr c′ n′ []= { Definition of foldr }

n′

foldr c′ n′ (x ⊕ xs)= { Definition of ⊕ }

foldr c′ n′ (xs ++ [x])= { Definition of (++ ) }

foldr c′ n′ (build (λc n. foldr c (foldr c n [x]) xs))= { Definition of foldr }

foldr c′ n′ (build (λc n. foldr c (c x (foldr c n [])) xs))= { Definition of foldr }

foldr c′ n′ (build (λc n. foldr c (c x n) xs))= { Lemma ?? }

foldr c′ (c′ x n′) xs

Matching e′ c′ n′ with n′ returns {e′ 7→ λc′ n′. n′}, and matching

(x ⊗ λc′ n′. foldr c′ n′ xs) c′ n′

withfoldr c′ (c′ x n′) xs

returns{(⊗) 7→ λx p c′ n′. p c′ (c′ x n′)}

By Theorem 3 with these conditions, we obtain

λxs. build (foldr (λx p c′ n′. p c′ (c′ x n′)) (λc′ n′. n′) xs)

The inner foldr can be simplified.

foldr (λx p c′ n′. c′ (f x) (p c′ n′)) (λc′ n′. n′) xs

= { η-expansion }

λc. foldr (λx p c′ n′. c′ (f x) (p c′ n′)) (λc′ n′. n′) xs c

= λc. ((λf. f c) ◦ foldr (λx p c′ n′. c′ (f x) (p c′ n′)) (λc′ n′. n′) xs)= { Promotion }

λc. foldr (λx p c′ n′. c′ (f x) (p c′ n′)) (λc′ n′. n′) xs

= { η-expansion }

λc n. foldr (λx p c′ n′. c′ (f x) (p c′ n′)) (λc′ n′. n′) xs n

= λc n. ((λf. f n) ◦ foldr (λx p c′ n′. c′ (f x) (p c′ n′)) (λc′ n′. n′) xs)= { Promotion }

λc. foldr (λx p r. p (c x r)) id xs

Finally, we obtain build-form of function reverse

reverse = λxs. build (λc. foldr (λx p r. p (c x r)) id xs)

2.2 Second-order Warm Fusion

In the previous Subsection, we have seen function reverse is warm fused by Theorem 3. On the other hand, asdescribed in [LS95], starting with the linear version of reverse does not succeed. Here, linear reverse is definedas

lrev xs = lrev′ xs []lrev′ [] ys = ys

lrev′ (x : xs) ys = lrev′ xs (x : ys)

This is because lrev′ has an accumulation parameter. Launchbury and Sheard introduce second-order cata-fusion to overcome the shortcoming. We follow their approach.

In transformation, they use first-order term rewriting and cannot instantiate higher-order variables whilerewriting. Therefore, they have to instantiate second-order cata-fusion. We do not have such restriction.

Hu et al. [HIT99] formulate systematic treatment of accumulations when function with accumulation issecond-order catamorphisms, which is generalization of foldr. They give calculation theorems for treatingaccumulations, but do not mention about how to obtain the operators in the theorem. We use higher-ordermatching to obtain these operators. We restrict their accumulation promotion theorems as the following twolemmas in the sense that one of the composed function is always foldr c n, and make the patterns in thetheorem more suitable for higher-order matching.

There are two ways to make promotion lemma second-order, instantiating f as (foldr c n◦) and (◦foldr c n).First, we show the former.

Lemma 4 (Second-order Fusion of Two foldr’s 1)

foldr c′ n′ ◦ e = e′ c′ n′

foldr c′ n′ ◦ (a ⊕ r) = (a ⊗ (λc′ n′. foldr c′ n′ ◦ r)) c′ n′

foldr c n ◦ foldr (⊕) e xs = foldr (⊗) e′ xs c n

The proof is done in similar way as Lemma 2.

Theorem 5 (Second-order Warm Fusion 1)

f [] = e

f (x : xs) = x ⊕ f xs

foldr c′ n′ ◦ e = e′ c′ n′

foldr c′ n′ ◦ (a ⊕ r) = (a ⊗ (λc′ n′. foldr c′ n′ ◦ r)) c′ n′

f = λxs ys. build (λc n. foldr (⊗) e′ xs c n ys)

The proof is done in similar way as Theorem 3.While linear reverse function lrev is warm fused by this theorem (See Appendix A), we present more difficult

example. Warm fusion [LS95] and Chitil’s approach [Chi99] cannot derive this result because of the restrictionstated in the above (see Appendix C).

Example 3 Consider to compute reverse of the longest increasing prefix.

dec xs = dec′ xs (−∞)dec′ [] = []dec′ (x : xs) y = if x > y then dec′ xs x ++ [x] else []

For example, dec [1, 3, 5, 4, 2] returns [5, 3, 1]. From the definition of dec′, we obtain

dec′ [] = λ . []dec′ (x : xs) = λy. if x > y then dec′ xs x ++ [x] else []

which defines a function foldr (⊕) e over a list where

e = λ . []x ⊕ p = λy. if x > y then p x ++ [x] else []

This is a second order foldr in the sense that it takes a list to yield a second-order function. Using theseoperators, we can calculate as follows

foldr c′ n′ ◦ e

= { Definition of e }

foldr c′ n′ ◦ λ . []= λ . foldr c′ n′ []= { Definition of foldr }

= λ . n′

foldr c′ n′ ◦ (a ⊕ r)= { Definition of (⊕) }

foldr c′ n′ ◦ λy. if x > y then r x ++ [x] else []= λy. foldr c′ n′ (if x > y then r x ++ [x] else [])= { Distribute foldr c′ n′ over if statement, foldr c′ n′ is strict }

= λy. if x > y then foldr c′ n′ (r x ++ [x]) else foldr c′ n′ []= { Definition of foldr }

λy. if x > y then foldr c′ n′ (r x ++ [x]) else n′

= { Definition of (++ ) }

λy. if x > y then foldr c′ n′ (build (λc n. foldr c (foldr c n [x]) (r x))) else n′

= { Shortcut Deforestation }

λy. if x > y then foldr c′ (foldr c′ n′ [x]) (r x) else n′

= { Definition of foldr }

λy. if x > y then foldr c′ (c′ x n′) (r x) else n′

We obtaine′ c′ n′ = λ . n′

(x ⊗ r) c′ n′ = λy. if x > y then r c′ (c′ x n′) x else n′

By Theorem 4, we obtain

f = λxs. build (λc n. foldr (λa r c n y. if a > y then r c (c a n) a else n) (λc n . n) xs c n (−∞))

Promotion simplify the inner foldr, and finally we obtain

f = λxs. build (λc n. foldr (λa r n y. if a > y then r (c a n) a else n) (λn . n) xs n (−∞))

The another instantiation of promotion theorem into second-order promotion lemma is as follows. We usethe fusion lemma as reverse direction in the sense that a single foldr is decomposed into two functions, foldrand mkfoldr which is reduced to be foldr. The aim of this lemma is to sweep out all the constructor abstractionvariables n and c into an accumulation parameter.

Lemma 6 (Second-order Fusion of Two foldr’s 2)

e r = e′ (foldr c n r)a ⊕ (a2 ◦ foldr c′ n′) = (a ⊗ a2) ◦ foldr (d2 c′ n′ a) (d1 c′ n′ a)

foldr (⊕) e xs = foldr (⊗) e′ xs ◦ mkfoldr c n xs

where mkfoldr c n as = uncurry foldr (mkfoldr′ c n as)mkfoldr′ c n [] = (c, n)mkfoldr′ c n (a : as) = let (c′, n′) = mkfoldr′ c n as in (d2 c′ n′ a, d1 c′ n′ a)

Proof. We prove by induction over xs. We omit the proof of base case. The calculation of inductive case is

lhs= foldr (⊕) e (x : xs)= x ⊕ foldr (⊕) e xs

= { Induction Hypothesis }

x ⊕ (foldr (⊗) e′ xs ◦ mkfoldr c n xs)= let (c′, n′) = mkfoldr c n xs

in x ⊕ (foldr (⊗) e′ xs ◦ foldr c′ n′)= let (c′, n′) = mkfoldr c n xs

in (x ⊗ foldr (⊗) e′ xs) ◦ foldr (d2 c′ n′ x) (d1 c′ n′ x)= foldr (⊗) e′ (x : xs) ◦ mkfoldr c n (x : xs)= rhs

¤

Theorem 7 (Second-order Warm Fusion 2)

f [] = e

f (x : xs) = x ⊙ f xs

foldr c n ◦ (a ⊙ r) = a ⊕ (foldr c n ◦ r)foldr c n ◦ e = e′ ◦ foldr c n

a ⊕ (a2 ◦ foldr c n) = (a ⊗ a2) ◦ foldr (d2 c n a) (d1 c n a)

f = λxs r. build (λc n. foldr (⊗) e′ xs (mkfoldr c n xs r))where mkfoldr c n as = uncurry foldr (mkfoldr′ c n as)

mkfoldr′ c n [] = (c, n)mkfoldr′ c n (a : as) = let (c′, n′) = mkfoldr′ c n as in (d2 c′ n′ a, d1 c′ n′ a)

Proof. Since the function f is described as

f [] = e

f (x : xs) = x ⊙ f xs

we obtainf = foldr (⊙) e (1)

By the equationfoldr c n ◦ (a ⊙ r) = a ⊕ (foldr c n ◦ r)

and the higher-order promotion lemma gives

foldr c n ◦ foldr (⊙) e xs = foldr (⊕) (foldr c n ◦ e) xs (2)

By the equationsfoldr c n ◦ e = e′ ◦ foldr c n

a ⊕ (a2 ◦ foldr c n) = (a ⊗ a2) ◦ foldr (d2 c n a) (d1 c n a)

and Lemma 7 gives

foldr (⊕) (foldr c n ◦ e) xs = foldr (⊗) e′ xs (mkfoldr c n xs r)where mkfoldr c n as = uncurry foldr (mkfoldr′ c n as)

mkfoldr′ c n [] = (c, n)mkfoldr′ c n (a : as) = let (c′, n′) = mkfoldr′ c n as in (d2 c′ n′ a, d1 c′ n′ a)

(3)

Equations (1-3) gives the conclusion of the theorem. ¤

We borrow the following example from [Voi02].

Example 4 (Partition) Consider a function partitioning a given list xs according to some predicate p.

part p xs = let f [] zs = zs

f (x : xs) zs = if p x then x : f xs zs

else f xs (zs ++ [x])in f xs []

For example, part even [1, 2, 3, 4, 5, 6] returns [2, 4, 6, 1, 3, 5]. Warm fusion [LS95] and Chitil’s approach [Chi99]are not applicable to the function (see Appendix D). On the other hand, we can apply Theorem 7. By definitionof part, we obtain

f [] = λzs. zs

f (x : xs) = λzs. if p x then x : f xs zs

else f xs (zs ++ [x])

Therefore we havee zs = zs

(x ⊙ r) zs = if p x then x : r zs else r (zs ++ [x])

Then, we calculate

foldr c n ◦ (a ⊙ r)= { Definition of (⊙) }

foldr c n ◦ (λzs. if p x then x : r zs else r (zs ++ [x]))= λzs. foldr c n (if p x then x : r zs else r (zs ++ [x]))= { Distribute foldr c n over if statement }

λzs. if p x then foldr c n (x : r zs) else foldr c n (r (zs ++ [x]))= { Definition of foldr }

λzs. if p x then c x (foldr c n (r zs)) else foldr c n (r (zs ++ [x]))

Matching the result with a ⊕ (foldr c n ◦ r) gives

a ⊕ r = λzs. if p x then c x (r zs) else r (zs ++ [x])

For the fourth precondition, we calculate

foldr c n ◦ e

= { Definition of e }

foldr c n ◦ (λzs. zs)= foldr c n

and obtaine′ = λzs. zs

For the last precondition, we calculate

a ⊕ (a2 ◦ foldr c n)= { Definition of (⊕) }

λzs. if p a then c a (a2 (foldr c n zs)) else a2 (foldr c n (zs ++ [a]))= { Definition of (++ ) }

λzs. if p a then c a (a2 (foldr c n zs)) else a2 (foldr c n (build (λc n. foldr c (foldr c n [a]) zs)))= { Shortcut Deforestation }

λzs. if p a then c a (a2 (foldr c n zs)) else a2 (foldr c (foldr c n [a]) zs)= { Definition of foldr }

λzs. if p a then c a (a2 (foldr c n zs)) else a2 (foldr c (c a n) zs)= λzs. (if p a then c a ◦ a2 else a2) (foldr c (if p a then n else c a n) zs)

Matching the result with (a ⊗ a2) ◦ foldr (d2 c n a) (d1 c n a) returns

(a ⊗ a2) r = (if p a then c a ◦ a2 else a2) r

d1 c n a = if p a then n else c a n

d2 c n a = c

By Theorem 7, we finally obtain

part p xs = build (λc n. foldr (⊗) e′ xs (mkfoldr c n xs []))where (a ⊕ a2) r = (if p a then c a ◦ a2 else a2) r

mkfoldr c n as = uncurry foldr (mkfoldr′ c n as)mkfoldr′ c n [] = (c, n)mkfoldr′ c n (a : as) = let (c′, n′) = mkfoldr′ c n as

in (c′, if p a then n′ else c′ a n′)

It is noted that first-order warm fusion theorem can apply to the second order function. For example,function init to return the initial list dropping the last element

init [] y = []init (x : xs) y = y : init xs x

can be warm fused by both first- and second-order warm fusion, while second-order warm fusion in [LS95] failsthis function.

3 Yicho System

Yicho is a system for specifying program transformation. The principal selling point is conciseness that manycalculation rules can be straightforwardly represented by the system, one of which is described in [YHT03].The conciseness of calculation rules is due to expressive higher-order patterns and powerful deterministichigher-order matching.

For example, we can define a promotion rule as

promotion :: RuleY -> ExpQ -> ExpY

promotion laws [| $f . foldr $oplus $e |] =

letm [| $e’ |] = laws [| $f $e |]

[| \x xs -> $otimes x ($f xs) |] = laws [| \x xs -> $f ($oplus x xs) |]

in ret [| foldr $otimes $e’ |]

This is straightforward translation of Lemma 1. Here, higher-order pattern

[| \x xs -> $otimes x ($f xs) |]

contributes the conciseness of the rule.Yicho can define intuitive program transformation strategy. For example, the strategy for applying promo-

tion if possible otherwise making tupled function and tupling is defined straightforwardly as

promotion <+ (tupling @@ mktuple)

3.1 Higher-order Pattern Matching

Most functional languages, like Haskell and ML, adopt a very restrictive pattern. Their pattern is only allowedto match with some fixed region near the root of the given tree and binds variables in the pattern to subtreesadjacent to this region. Thus, it is neither possible to match with a region far from the root, nor bind to aregion other than complete subtrees.

For program calculation, it is convenient if programmer can specify the arbitrary far region from the rootsatisfying some condition. Higher-order patterns enable such matching and bindings. The characteristic ofhigher-order pattern is occurrence of free variables in functional part. The arguments of free variables are ableto specify arbitrary far region from the node matched with the root of the free variables.

Generally, higher-order matching returns many solutions. Obviously, it does not suit with functional pro-gramming which conveys a single value, unlike nondeterministic logic programming with backtracking mecha-nism. We take an approach restricting matching algorithm to return at most a single match by using naturalorder on the solutions. This approach is reasonable when the object program is scaling up. Specification ofour matching algorithm is simply formalized in terms of the following total order.

Definition 1 (LT Order) At least, left-to-right, top-down abstraction order on terms according to x is de-fined as follows

order x E F = let cmp = compare (count x E) (count x F )in if cmp = EQ then order′ x E F else cmp

count x x = 1count x (E1 E2) = count x E1 + count x E2

count x = 0order′ x x x = EQ

order′ x x = GT

order′ x x = LT

order′ x = EQ

order′ x (E1 E2) (F1 F2) = let cmp = order′ x E1 F1

in if cmp == EQ then order′ x E2 F2 else cmp

order′ x (λy. E) (λy. F ) = order′ x E F

Firstly, the number of x appeared in given expression is compared, and then abstraction position is comparedby left-to-right, top-down order. For example, the following terms are lined in decreasing order2.

x (1 + 1) >x x + (1 + 1) >x (1 + 1) + x >x x (x 1) >x x + x

2It is noted that x + x is a syntax sugar of (+) x x.

Match is compared by this order on targets according to all the local variables. For example, matchingp (λx. x + x) with (1 + 1) + (1 + 1) returns { p 7→ λx. x (1 + 1) }.

In this paper, the notation of program is the same as [TH00] except that quote bracket is denoted as [|[ ]]| not≪≫, and unquote is denoted as $e (unquote is put before the quoted expression) not e$. These notion followTemplate Haskell.

3.2 Implementation by Embedding

We determine to implement Yicho by embedding. We design a monadic combinator library for programtransformation in Haskell. The combinator library uses higher-order patterns as first-class values which canbe passed as parameters, constructed by smaller ones in compositional way, returned as values, etc. As aresult, our libraries provide more flexible binding than first-order ones, and enables more abstract and modulardescription of program transformation.

Since the combinator is embedded in Haskell, users do not need to learn other languages than Haskell, allwhat they need to do is know about functions we prepare, and enjoy all the benefits of the host language,such as type checking, module system, develop environment, etc. That is all the advantages of domain-specificembedded languages [Hud96]. Thanks to the mechanism of Template Haskell [SP02] which is meta-extension ofHaskell, all the transformation specified using our libraries are expanded at compile time. Our library, togetherwith all codes in this paper, has been tested on GHC 6.2.1.

Domain-specific language in meta-programming is promising approach [COST03]. Among functional meta-programming languages, i.e., Template Haskell, MetaML [Met00], and MetaOCaml [CTHL03, Met03], onlyTemplate Haskell provides a way to construct and pattern match with abstract syntax trees. This is matchedwith our aim. We want to change the semantics of patterns. Therefore, we introduce reconstruction of abstractsyntax trees before passing it to compiler.

Firstly, as a usual construction of combinator libraries, we consider what data type our combinator convey,and design basic combinators.

3.3 Data Type of Program

We use meta-programming features to manipulate programs as values. Template Haskell provides a mechanismto handle abstract syntax trees of Haskell in Haskell itself. Enclosing brackets [| |] (quote) make programsabstract syntax tree whose type is ExpQ (i.e., Q Exp), and the inverse operation is unquote described by a dollar$. For example, given a function to calculate the sum of a given list, sum, which has type3 [Int] -> Int,[| sum |] has type ExpQ, whereas $([| sum |]) has the same type as sum, i.e., [Int] -> Int.

During program transformation, the data representation of program should be a list of closures, becausethe inner representation of a program is an expression with an environment and we deal with failure of trans-formation.

Monad is a way to structure programming and provides such an easy treatment of program. One mayconstruct a new monad, combining aspects of both operating lookup and update of environment and keepingtrack of a list of expressions. A more cheap way is to define a combined monad consisting of smaller ones.

type ExpY = Y ExpQ

type Y e = StateT Subst (ListT Q) e

Here, Subst is an environment, a mapping from variables to closed expressions, and StateT and ListT aremonad transformers which are defined in Haskell Hierarchical Libraries of GHC. Intuitively, state transformerStateT conveys states and List transformer ListT conveys multiple values.

We use ret to lift ExpQ into ExpY. We use runY back to ExpQ from ExpY. The relationship of those types issummarized in Fig. 1.

3.4 Basic Combinators

Our combinator has five important constructs; match (<==), rule (==>), deterministic choice (<+), case-selectioncaseM, and sequence (>>). Types of the basic combinators are summarized in Fig 2.

The essential construct is match

(<==) :: ExpQ -> ExpQ -> Y ()

pat <== term

3Strictly speaking, the type of function sum is Num a ⇒ [a] → a in Haskell. Here, for simplicity, we ignore type classes andpolymorphism.

� ���� ����

���

� � ��

���

Value Meta Code Meta Code with

Environment

Figure 1: Relationship of Types

Match (<==) :: ExpQ -> ExpQ -> Y ()

Rule (==>) :: ExpQ -> ExpQ -> RuleY

Choice (<+) :: ExpY -> ExpY -> ExpY

Case Alternative caseM :: ExpQ -> [RuleY] -> ExpY

Sequence (>>) :: ExpY -> ExpY -> ExpY

Figure 2: Basic Combinators

which yields a substitution (match) that makes patterns (pat) and terms (term) to be equal.For example, matching

[| \a x -> $oplus a (bign x, sum x) |]

<== [| \a x -> if a > sum x

then a : bign x

else bign x |]

yields a substitution

{ $oplus := \x (b,s) ->

if x > s then x : b else b }

Note that annotation $ means unquote. Thus, the above match is equivalent to

{ oplus := [| \x (b,s) ->

if x > s then x : b else b |] }

Function $oplus is a second-order pattern and to obtain the match we used deterministic higher-order match-ing [YHT04].

A transformation rule is taking an expression and returns a list of closures.

type RuleY = ExpQ -> ExpY

A transformation rule is constructed by operator (==>).

(==>) :: ExpQ -> ExpQ -> RuleY

(pat ==> body) term = do pat <== term

ret body

Here, function ret implicitly applies the match kept in monad to body.Operator (<+) is deterministic choice. It returns the first argument if it is not empty. Otherwise, it returns

the second argument.Using the operator, meta version of case is to be

caseM :: ExpQ -> [RuleY] -> ExpY

caseM sel (r:rs) =

r sel <+ caseM sel rs

For simplicity, we use long arrows (<===) and (===>). They are the same as short arrows except types are

(<===) :: ExpQ -> ExpY -> Y ()

(===>) :: ExpQ -> ExpY -> RuleY

Sequencing of binding new environments can be realized by combining matches by operator (>>).

(pat1 <== term1) >> (pat2 <== term2)

which can be written as sequence of match using do notation.

do pat1 <== term1

pat2 <== term2

Using these important combinators, we can write many new combinators. For example, combinator successalways returns the input value and combinator try applies a given rule if possible

success :: RuleY

success [| $x |] = ret [| $x |]

try :: RuleY -> RuleY

try r = r <+ success

From programmer, these new combinators seem not different from built-in combinators. This means extensi-bility of our library.

3.5 Syntax Sugar

For simplicity, we prepare two syntax sugar letm and casem. Intuitive meaning of these syntax is meta versionof let and case respectively. Expression

letm p1 = e1

p2 = e2

...

pn = en

in b

means matching p1 with e1 and adding the result to environment, under this new environment matching p2

with e2 and adding the result to environment and so on, and finally returns b with the final environment. Itis noted that the recursive definition can not be represented in letm; matches are evaluated sequentially. Thisletm expression is transformed into

foldr1 (>>) (zipWith (<===) [p1,p2,...,pn] [e1,e2,...,en] ++ [ret b])

For casem construct, expression

casem b of

p1 -> e1

p2 -> e2

...

pn -> en

means firstly trying to match p1 with b and if succeeded, then add the result of this match to environmentand e1 is returned. Otherwise, evaluation proceeds to matching p2 with b, and so forth.

This casem expression is transformed into

foldr1 (<+) (zipWith (===>) [p1,p2,...,pn] [e1,e2,...,en]) b

Pattern variables are defined by function pvars. For example, expression

do [oplus,e] <- pvars ["name1","name2"]

defines oplus and e as pattern variables. The unquoted variable $oplus and $e corresponds "$name1" and"$name2" respectively. Simultaneously, substitution { oplus := [| \$name1 |], e := [| \$name2 |]} isbound into environment manipulated in the Y monad. This variable declaration is bother and routine work.Therefore, we get rid of burden of this declaration from users. Preprocesser collects all the pattern variablesoccuring in the body of a function, and add the pattern variable declaration into the body.

Though code patterns are prohibited to appear in patterns in Haskell, we allow it by the following syntactictransformation. Function definition

f [| p1 |] [| p2 |] ... [| pn |] = b

is transformed into

f _exp1_ _exp2_ ... _expn_ = do

[v1,v2,...vk] <- pvars ["v1","v2",...,"vk"]

foldr (>>) b (zipWith (<==) [[| p1 |],...,[| pn |]] [_exp1_,_exp2_,...,_expn_])

4 Coding Warm Fusion in Yicho

We demonstrate a calculation carrying problem of warm fusion. Thanks to the expressive power of higher-orderpatterns, we can describe warm fusion lemma’s almost as it is. At the top level, warm fusion is done by thefollowing expression.

warmFusion myRules [| reverse |]

It returns the following build form.

\xs -> build (\c n -> foldr (\c’ b’ a’ -> b’ (c c’ a’)) (\n -> n) xs n)

This expansion is done at compile time, and GHC entails shortcut deforestation by rewriting rule [PTH01].Function warmFusion takes rules and an expression (ExpQ) and returns an expression (ExpY). Warm fusion

is either first-order fWarmFusion or second-order sWarmFusion. We try first-order first, and returns the resultif succeeds, and otherwise returns the result of second-order warm fusion.

warmFusion :: RuleY -> ExpQ -> ExpY

warmFusion laws = fWarmFusion laws <+ sWarmFusion laws

First-order warm fusion fWarmFusion follows Theorem 3.

fWarmFusion :: RuleY -> ExpQ -> ExpY

fWarmFusion laws [| $f |] =

letm [| $e |] = laws [| $f [] |]

[| \x xs -> $oplus x ($f xs) |] = laws [| \x xs -> $f (x:xs) |]

[| $e’ |] = laws [| \c’ n’ -> foldr c’ n’ $e |]

[| \x xs c’ n’ -> ($otimes x (\c’ n’ -> foldr c’ n’ xs)) c’ n’ |]

= laws [| \x xs c’ n’ -> foldr c’ n’ ($oplus x xs) |]

[| $exp’ |] = simplify laws [| foldr $otimes $e’ |]

in ret [| \xs -> build ($exp’ xs) |]

It has the same type as function warmFusion. At the first line of the body, we declare that e, oplus, e’, andotimes are free variables. At the second line, f is substituted into expression [| $f [] |], and then rule lawsis applied. The role of rule laws is to unfold the definition of $f []. The result is matched with [| $e |],and e is bounded. The code from 1-6 lines in the body corresponds the precondition of Theorem 3.

Function simplify simplifies the code by promotion lemma, as we show in examples.

simplify :: RuleY -> ExpQ -> ExpY

simplify laws [| $exp |] = do

let (ps,[x,c,n]) = genPE "cn" 3

exp’ <- try (promotion laws) [| (\x -> x $c) . $exp |]

exp’’<- try (promotion laws) [| (\x -> x $n) . $exp’ |]

laws (lamE ps [| $exp’’ $x |])

At first line in the body, function genPE, which is defined in Template Haskell modules, generates patternvariables ps and corresponding variables [x,c,n]. The code of 4-5 lines tries to apply promotion lemmato simplify the given expression. It is noted that, if we assume the correctness of functions promotion andlaws, the meaning of the result is the same as a given expression. We can prove the correctness of this codeindependent of the other code. This means high modularity of our library.

On the other hand, second-order warm fusion is defined as follows.

sWarmFusion :: RuleY -> ExpQ -> ExpY

sWarmFusion laws [| $f |] =

letm [| $e |] = laws [| $f [] |]

[| \x xs -> $oplus x ($f xs) |] = laws [| \x xs -> $f (x:xs) |]

[| $e’ |] = laws [| \c’ n’ -> foldr c’ n’ . $e |]

[| \a r c’ n’ -> ($otimes a (\c’ n’ x -> foldr c’ n’ (r x))) c’ n’ |]

= laws [| \a r c’ n’ -> foldr c’ n’ . ($oplus a r) |]

[| $exp’ |] = simplify laws [| foldr $otimes $e’ |]

in ret [| \xs y -> build (\c n -> $exp’ xs c n y) |]

This is straightforward translation of Lemma 5.The rule myRules expands function definitions, distributes function over if statement, and tries to apply

shortcut deforestation.

myRules = try foldr_build @@ funcif @@ myDef

Here, operator (@@) represents composition of monadic functions.

f @@ g = \x -> f x >>= g

The functions to be transformed is defined as follows. Here, bracket [d| |] is the quotation for declaration.

def = [d| reverse [] = []

reverse (a:x) = reverse x ++ [a]

(++) x y = build (\c n -> foldr c (foldr c n y) x )

map f [] = []

map f (a:x) = f a : map f x

foldr c n [] = n

foldr c n (x:xs) = c x (foldr c n xs)

dec’ [] = \y -> []

dec’ (x:xs) = \y -> if x > y then dec’ xs x ++ [x] else []

|]

These definitions are expanded automatically by splicing denoted by $( ).

$(def)

To make unfolding rules of these definitions, we prepare the built-in function mkrules.

myDef = mkrules "Testing.PPL2005Def" def

Here, second argument of mkrules is the name of module where it is spliced.We distribute a function over if statement4.

funcif [| $e |] =

casem [| $e |] of

[| $c (\a b c d -> d (if a then b else c)) |]

-> funcif [| $c (\a b c d -> if a then d b else d c) |]

[| $c |] -> ret [| $c |]

Shortcut deforestation rule is defined as follows.

foldr_build [| $x |] =

letm [| ($c :: forall a d. (forall c. (a -> c -> c) -> c ->

(forall b. (a -> b -> b) -> b -> b) -> c) -> d)

(\k z g -> foldr k z (build g)) |] = ret [| $x |]

in ret [| $c (\k z g -> g k z) |]

4At the moment, we omit strictness analysis.

Here, since g is rank 2 polymorphic function, we need explicit type declaration. It is noted that type is inferencedin a single code surrounded by quotation bracket [| |]. This type declaration is used just for making compilerquite and is not used for static type inference of our code. Transformation is done by replacing arguments ofthe context variable c.

The second-order warm fusion is also applicable by function warmFusion.

warmFusion myRules [| dec’ |]

This returns

\xs y -> build (\c n -> foldr (\c’ b’ a’ x -> if c’ > x

then b’ (c c’ a’) c’’

else a’) (\n x -> n) xs n y)

Theorem 7 can be programmed in the similar way.

5 Conclusion and Related Work

We describe the implementation of warm fusion by program calculation system Yicho. This implementation isconcise and modular. Firstly, thanks to the expressive power of higher-order patterns and powerful deterministicmatching, we can reduce warm fusion code into less than 100 lines. Warm fusion theorems are straightforwardlyrepresented almost as it is. Secondly, our rules are constructive and thus modular. Small rules are glued intobig rules by combinators.

Stratego [Vis01] is a program transformation system based on rewriting strategies. It is a distributedimplementation which enables warm fusion [JV00]. Their approach is essentially rule-based fold/unfold, i.e,unfolding when necessary. Transformation rules are defined in imperative fashion which is generally longer thandeclarative definition. The warm fusion transformer becomes complex. It consists of 750 lines. On the otherhand, our transformation is calculation-based. Functions are firstly settled down into stylized form and applieddeclarative calculation theorems. We do not use any explicit unfolding rules. This reduces the complexity oftransformation rules and the amount of code. The most contributor of the conciseness is expressive powerof higher-order patterns. It also improves readability of program. The program is almost the same as thecalculation theory. Stratego has advantage in specifying generic term traversal strategies. They are used tospecify the place to which transformation rule applies. We use higher-order patterns and do not use explicittraversal strategies but we use LT-order in higher-order matching algorithm. As a result, the code size of warmfusion in Yicho is one tenth as long as that in Stratego.

Our combinator library has high extensibility; user can make new combinators easily and user does notneed to distinguish built-in combinator from user-defined combinators. We believe that many calculation rulesare concisely represented by our library, one of which is described in [YHT03].

In Template Haskell, type of all expressions is simply Exp. For example, the type of both function sum andlist [1,2,3] is Exp. Our combinator library follows this. In the other words, our language is untyped, does notdo type inference, and therefore does not catch statical type errors. Embedding type inference features in ourmonad is future work. On the other hand, MetaOcaml and MetaML have language support. They have moreintimate types that can detect statical type errors. For example, in MetaOCaml the above codes are typedas (’a, int list -> int list) code, (’a, int list) code, and (’a, int) code respectively. But theselanguages do not support direct manipulation of abstract syntax trees, which does not match our aims.

We choose deterministic higher-order matching algorithm. This is reasonable choice for transforming a largeprogram, because they have linear time algorithm. Comparing with general exponential higher-order matching,our matching suits with scaling up. In [Hec88], this discussion appears and they implemented deterministicand non-deterministic TrafoLa. In non-deterministic case, heavy backtracking is necessary.

In this paper, we show warm fusion on catamorphisms (foldr). To carry out the dual anamorphic fusion, thedual calculational law is needed. For anamorphism (unfoldr), we can use destroy and unfoldr [Sve02] insteadof foldr and build. More general normal form, hylomorphisms [TM95], deal with both cases simultaneously.The derivation of hylomorphisms from recursive definitions and warm fusion of it is described in [HIT96].

Acknowledgment

The work is supported by the Comprehensive Development of e-Society Foundation Software Program of Min-istry of Education, Culture, Sports, Science and Technology, Japan.

References

[Bir98] Richard Bird. Introduction to Functional Programming using Haskell (second edition). PrenticeHall, 1998.

[Chi99] Olaf Chitil. Type inference builds a short cut to deforestation. In ACM SIGPLAN InternationalConference on Functional Programming, volume 34, pages 249–260, Paris, France, September 1999.ACM Press.

[Chi00] Olaf Chitil. Type-Inference Based Short Cut Deforestation (nearly) without Inlining. In Chris Clackand Pieter Koopman, editors, Proceedings of 11th International Workshop on Implementation ofFunctional Languages (1999), number 1868 in LNCS, pages 19–36, Netherlands, unknown 2000.Springer.

[COST03] Krzysztof Czarnecki, John T. O’Donnell, Jorg Striegnitz, and Walid Taha. DSL implementation inMetaOCaml, Template Haskell, and C++. In Domain-Specific Program Generation, pages 51–72,2003.

[CTHL03] Cristiano Calcagno, Walid Taha, Liwen Huang, and Xavier Leroy. Implementing multi-stage lan-guages using asts, gensym, and reflection. In GPCE, pages 57–76, 2003.

[GHC] The glasgow haskell compiler. http://www.haskell.org/ghc.

[Gil96] Andrew J. Gill. Cheap Deforestation for Non-strict Functional Languages. PhD thesis, GlasgowUniversity, January 1996.

[GLP93] Andrew Gill, John Launchbury, and Simon L. Peyton Jones. A short cut to deforestation. In Pro-ceedings of the 6th International Conference on Functional Programming Languages and ComputerArchitecture (FPCA’93), pages 223–232, Copenhagen, Denmark, June 1993. ACM Press.

[Hec88] R. Heckmann. A functional language for the specification of complex tree transformation. InProc. ESOP, volume 300 of LNCS, pages 175–190, 1988.

[HIT96] Zhenjiang Hu, Hideya Iwasaki, and Masato Takeichi. Deriving structural hylomorphisms fromrecursive definitions. In ACM SIGPLAN International Conference on Functional Program-ming(ICFP’96), pages 73–82, 1996.

[HIT99] Zhenjiang Hu, Hideya Iwasaki, and Masato Takeichi. Calculating accumulations. New GenerationComputing, 17(2), 1999.

[Hud96] Paul Hudak. Building domain-specific embedded languages. ACM Comput. Surv., 28(4es):196,1996.

[JV00] Patricia Johann and Eelco Visser. Warm fusion in stratego: A case study in the generation ofprogram transformation systems. Technical Report Technical Report UU-CS-2000-43, Institute ofInformation and Computing Sciences, Utrecht University, 2000.

[LS95] John Launchbury and Tim Sheard. Warm fusion: Deriving build-catas from recursive definitions.In Conference on Functional Programming Languages and Computer Architecture, pages 314–323,La Jolla, CA, USA, June 1995. ACM.

[Met00] MetaML, October 2000. Available online from http://www.cse.ogi.edu/PacSoft/projects/metaml/index.html.

[Met03] MetaOCaml: A compiled, type-safe multi-stage programming language, 2003. Available online fromhttp://www.metaocaml.org/.

[PTH01] Simon L. Peyton Jones, Andrew Tolmach, and Tony Hoare. Playing by the rules: rewriting as apractical optimisation technique in ghc. In Haskell Workshop, 2001.

[SF93] T. Sheard and L. Fegaras. A fold for all seasons. In Conference on Functional ProgrammingLanguages and Computer Architecture, pages 233–242, 1993.

[SP02] Tim Sheard and Simon L. Peyton Jones. Template metaprogramming for Haskell. In HaskellWorkshop, pages 1–16, Pittsburgh, Pennsylvania, May 2002.

[Sve02] Josef Svenningsson. Shortcut fusion for accumulating parameters & zip-like functions. In ICFP,pages 124–132, 2002.

[TH00] Masato Takeichi and Zhenjiang Hu. Calculation carrying programs: How to code program transfor-mations (invited paper). In International Sumposium on Principles of Software Evolution (ISPSE2000), Kanazawa, Japan, November 2000. IEEE Press.

[TM95] A. Takano and E. Meijer. Shortcut deforestation in calculational form. In Conference on FunctionalProgramming Languages and Computer Architecture, pages 306–313, 1995.

[Vis01] Eelco Visser. Stratego: A language for program transformation based on rewriting strategies. systemdescription of stratego 0.5. In A. Middeldorp, editor, Rewriting Techniques and Applications, volume2051 of LNCS, pages 357–362. Springer-Verlag, 2001.

[Voi02] Janis Voigtlander. Concatenate, reverse and map vanish for free. In Simon Peyton Jones andMitchell Wand, editors, Seventh International Conference on Functional Programming, Pittsburgh,Pennsylvania, Proceedings, volume 37 of SIGPLAN Notices, pages 14–25. ACM Press, October2002.

[Wad90] P. Wadler. Deforestation: transforming programs to eliminate trees. Theoretical Computer Science,73(2):231–248, 1990.

[YHT03] Tetsuo Yokoyama, Zhenjiang Hu, and Masato Takeichi. Deterministic second-order patterns inprogram transformation. In Maurice Bruynooghe, editor, International Symposium on Logic-basedProgram Synthesis and Transformation(LOPSTR ’03), pages 165–178, Uppsalla, Sewden, August2003.

[YHT04] Tetsuo Yokoyama, Zhenjiang Hu, and Masato Takeichi. Deterministic second-order patterns. In-formation Processing Letters, 89(6):309–314, March 2004.

A Linear Reverse

Example 5 (Linear Reverse) Consider a function to compute reversed list in linear time:

lrev xs = lrev′ xs []lrev′ [] ys = ys

lrev′ (x : xs) ys = lrev′ xs (x : ys)

foldr c n (lrev xs)= { Def. of lrev }

foldr c n (lrev xs [])= { Identity }

foldr c n (lrev (foldr (:) [] xs) [])= { Promotion }

foldr c n (foldr (λx p ys. p (x : ys)) id xs [])= { Promotion

foldr c n ◦ id

= foldr c n

foldr c n ◦ (λys. r (a : ys))= λys. foldr c n (r (a : ys))

}foldr (λa r ys. r (a : ys)) (foldr c n) xs []

B Warm Fusion of (++ )

Example 6 (Append) Consider a function to concatenate given two lists:

[] ++ ys = ys

(x : xs) ++ ys = x : (xs ++ ys)

Promotion into foldr (:) [] gives function foldr (λx r ys. x : r ys) id. Promotion lemma transforms

(foldr c n◦) ◦ foldr (λx r ys. x : r ys) id.

intofoldr (λx r ys. c x (r ys)) (foldr c n)

Therefore, build-form of (++ ) is

λxs ys. build (λc n. foldr (λx r ys. c x (r ys)) (foldr c n) xs ys)

On the other hand, lemma 4 gives calculation

(foldr c n◦) ◦ foldr (λx r ys. x : r ys) id

= { foldr c n ◦ id = foldr c n

foldr c n ◦ (λys. x : r ys)= { def. of (◦) }

λys. foldr c n (x : r ys)= λys. c x (foldr c n (r ys))

}λxs. foldr (λx r c′ n′ ys′. c′ x (r c′ n′ ys′)) foldr xs c n

= { Promotion }

λxs. foldr (λx r c′ n′ ys′. n′ x (r c′ n′ ys′)) (λx c′ n′. foldr c′ n′ x) xs c n

= { Promotion }

λxs ys. foldr (λx r c′ n′ ys′. c′ x (r n′ ys′)) (λc′ n′. foldr c′ n′ ys) xs c n

= { Promotion }

λxs ys. foldr (λx r n′ ys′. c x (r n′)) (λn′. foldr c n′ ys) xs n

= { Promotion }

λxs ys. foldr c (foldr c n ys) xs

Therefore, build-form of (++ ) is

λxs ys. build (λc n. foldr c (foldr c n ys) xs)

C Warm Fusion of dec

We write cataList (n, c) as g for brevity. The additional rules for second-order promotion is

R′

Cons= {s1 → r1, g (s2 x) → r2 (g x), g y → z}

The reduction sequence is as follows.

R∪R′

Cons

⊢ λ(r1, r2). λz. g (if s1 > y then append (s2 s1) (Cons(s1,Nil())) else Nil())→ λ(r1, r2). λz. if s1 > y then g (append (s2 s1) (Cons(s1,Nil()))) else g (Nil())→ λ(r1, r2). λz. if s1 > y then g (append (s2 s1) (Cons(s1,Nil()))) else n()→ λ(r1, r2). λz. if s1 > y

then g (buildList (λ(n, c). cata

List (λ(). g (Cons(s1,Nil())), c) (s2 s1)))else n()

→ λ(r1, r2). λz. if s1 > y then cataList (λ(). g (Cons(s1,Nil())), c) (s2 s1))) else n()

→ λ(r1, r2). λz. if r1 > y then cataList (λ(). g (Cons(r1,Nil())), c) (s2 r1) else n()

→ λ(r1, r2). λz. if r1 > y then cataList (λ(). (c (r1, g (Nil()))), c) (s2 r1) else n()

→ λ(r1, r2). λz. if r1 > y then cataList (λ(). (c (r1, n())), c) (s2 r1) else n()

The reduction is terminated. Since y and s2 occur free, this expression is invalid.

D Type Inference Based Warm Fusion of part

Function part′ with type judgment is as follows.

{p : Int → Bool, (++) : [Int] → [Int] → [Int]

(:) : Int → [Int] → [Int], [] : [Int]}⊢ let part’ : [Int] → [Int] → [Int]

= λxs : [Int]. λzs : [Int].case xs of {

[] → zs

y:ys → if p y then y : part’ ys zs else part’ ys (zs ++ (y : []))

in part’ xs []

The first argument of (++) should [Int], and because of the first alternative of case the result type of part’is [Int].


Recommended