+ All Categories
Home > Documents > Refactoring Haskell Programs Huiqing Li Computing Lab, University of Kent

Refactoring Haskell Programs Huiqing Li Computing Lab, University of Kent

Date post: 20-Dec-2015
Category:
View: 214 times
Download: 1 times
Share this document with a friend
36
Refactoring Haskell Programs Huiqing Li Computing Lab, University of Kent www.cs.kent.ac.uk/projects/refactor- fp/
Transcript

Refactoring Haskell Programs

Huiqing Li

Computing Lab, University of Kent www.cs.kent.ac.uk/projects/refactor-fp/

04/18/23 TCS 2

Outline

Refactoring HaRe: The Haskell Refactorer Implementation of HaRe Formalisation of Haskell Refactorings Future Work

04/18/23 TCS 3

Refactoring

What? Changing the structure of existing code without changing its behaviour.

module Main (main) where

f z y = y : f z (y + z)

main y = print $ f 1 10

module Main (main) where

f y = y : f (y + 1)

main = print $ f 10

Example:

04/18/23 TCS 4

HaRe – The Haskell Refactorer

A tool for refactoring Haskell 98 programs. Full Haskell 98 coverage. Driving concerns: usability and

extensibility. Integrated with the two program editors:

(X)Emacs and Vim. Preserves both comments and layout style

of the source.

04/18/23 TCS 5

HaRe – The Haskell Refactorer

Implemented in Haskell, using Programatica’s frontends and Strafunski’s generic traversals. Programatica: a system implemented in

Haskell for the development of high-assurance software in Haskell.

Strafunski: A Haskell library for supporting generic programming in application areas that involve term traversals over large abstract syntaxes.

04/18/23 TCS 6

Refactorings Implemented in HaRe

Structural Refactorings

Module Refactorings

Data-Oriented Refactorings

04/18/23 TCS 7

Refactorings Implemented in HaRe

Structural Refactorings Generalise a definition

module Main (main) where

f y = y : f (y + 1)

main = print $ f 10

module Main (main) where

f z y = y : f z (y + z)

main y = print $ f 1 10

04/18/23 TCS 8

Refactorings Implemented in HaRe Structural Refactorings (cont.)

Rename an identifier Promote/demote a definition to widen/narrow its scope Delete an unused function Duplicate a definition Unfold a definition Introduce a definition to name an identified expression Add an argument to a function Remove an unused argument from a function

04/18/23 TCS 9

Refactorings Implemented in HaRe

Module Refactorings

module Test (f) where

f y = y : f (y + 1) module Main where import Test

main = print $ f 10

module Test ( ) where

module Main whereimport Test

f y = y : f (y + 1) main = print $ f 10

Move a definition from one module to another module

04/18/23 TCS 10

Refactorings Implemented in HaRe

Module Refactorings (cont.) Clean the imports Make the used entities explicitly imported Add an item to the export list Remove an item from the export list

04/18/23 TCS 11

Refactorings Implemented in HaRe

Data-oriented Refactorings From concrete to abstract data-type (ADT),

which is a composite refactoring built from a sequence of primitive refactorings.

04/18/23 TCS 12

Refactorings Implemented in HaRe

04/18/23 TCS 13

Refactorings Implemented in HaRe

04/18/23 TCS 14

TS: token stream; AST: annotated abstract syntax tree; MI: module information;

Programatica (lexer, parser,

type checker,module

analysis)

TS

AST + MI

Program

TS’

analysis and transformatio

n using

Strafunski(with DrIFT)

AST’

extract program

from token stream

Program

Implementation of HaRe

04/18/23 TCS 15

The Architecture of HaRe

Composite Refactorings

Elementary Refactorings

RefacUtils (HaRe_API)

Programatica Strafunski (with DrIFT)

RefacLocUtils

04/18/23 TCS 16

Formalisation of Refactorings Advantages:

Clarify the definition of refactorings in terms of side-conditions and transformations.

Improve our confidence in the behaviour-preservation of refactorings.

Guide the implementation of refactorings.

Challenges: Haskell is a non-trivial language. Haskell does not have an officially defined

semantics.

04/18/23 TCS 17

Formalisation of Refactorings

Our Strategy: Start from a simple language (letrec). Extend the language gradually to formalise

more complex refactorings.

04/18/23 TCS 18

Formalisation of Refactorings

The specification of a refactoring contains four parts:

The representation of the program before the refactorings, say P1

The side-conditions for the refactoring. The representation of the program after the

refactorings, say P2.

A proof showing that P1 and P2 have the same

functionality under the side-conditions.

04/18/23 TCS 19

Formalisation of Refactorings

The -calculus with letrec (letrec) Syntax of letrec terms.

E ::= x | x.E | E1 E2 | letrec D in E D ::= | xi=Ei | D, D

Use the call-by-name semantics developed by Zena M. Ariola and Stefan Blom in the paper Lambda Calculi plus letrec.

04/18/23 TCS 20

Formalisation of Generalisation

Recall the example

module Main (main) where

f y = y : f (y + 1)

main = print $ f 10

module Main (main) where

f z y = y : f z (y + z)

main = print $ f 1 10

04/18/23 TCS 21

Formalisation of Generalisation

Formal definition of Generalisation using letrec

Given the expression:

Assume E is a sub-expression of Ei, and Ei= C[E].

letrec x1=E1, ..., xi =Ei , ..., xn =En in E0

04/18/23 TCS 22

Formalisation of Generalisation

Formal definition of Generalisation using letrec

The condition for generalising the definition xi=Ei on E is:

xiFV(E ) Æ 8x, e: (x 2FV(E ) Æ e 2 sub(Ei, C) ) x 2FV(e))

module Main (main) where

f y = y : f (y + 1)

main = print $ f 10

04/18/23 TCS 23

Formalisation of Generalisation

Formal definition of Generalisation using letrec

The condition for generalising the definition xi=Ei on E is:

xiFV(E ) Æ 8x, e: (x 2FV(E ) Æ e 2 sub(Ei,C) ) x 2FV(e))

module Main (main) where

f y = y : f (y + 1)

main = print $ f 10

04/18/23 TCS 24

Formalisation of Generalisation Formal definition of Generalisation using letrec

The condition for generalising the definition xi=Ei on E is:

xiFV(E ) Æ 8x, e: (x 2FV(E ) Æ e 2 sub(Ei,C) ) x 2FV(e))

module Main (main) where

f y = y : f (y + 1)

main = print $ f 10

04/18/23 TCS 25

Formalisation of Generalisation Formal definition of Generalisation using letrec

After generalisation, the original expression becomes:

letrec x1= E1 [xi := xiE],

..., xi = z.C[z][xi:=xi z],

..., xn = En [xi:= xi E]

in E0 [xi:= xi E],

where z is a fresh variable.

module Main (main) where

f z y = y : f z (y + z)

main = print $ f 1 10

module Main (main) where

f y = y : f (y + 1)

main = print $ f 10

04/18/23 TCS 26

Formalisation of Generalisation

Formal definition of Generalisation using letrec

Proof. Decompose the transformation into a number of sub steps, if each sub step is behaviour-preserving, then the transformation is behaviour-preserving.

04/18/23 TCS 27

Formalisation of Generalisation

Step1: add definition x = z.C[z] , where x and z are

fresh variables, and C[E]=Ei.

module Main (main) where

f y = y : f (y +1)

x z y = y : f ( y + z)

main = print $ f 10

letrec x1=E1, ..., xi =Ei, x = z.C[z], ..., xn =En in E0

Step 2: Replace Ei with x E. (Note: Ei = x E)

04/18/23 TCS 28

Step 2: Replace Ei with x E. (Note: Ei = x E)

module Main (main) where

f y = x 1 y

x z y = y : f ( y + z)

main = print $ f 10

letrec x1=E1, ..., xi = x E, x = z.C[z], ..., xn =En in E0

Step 3: Unfolding xi in the right-hand side of x.

Formalisation of Generalisation

04/18/23 TCS 29

Formalisation of Generalisation

Step 3: Unfolding xi in the right-hand side of x.

module Main (main) where

f y = x 1 y

x z y = y : x 1 ( y + z)

main = print $ f 10

letrec x1=E1, ..., xi = x E, x = z.C[z] [x_i:= x E], ..., xn =En in E0

Step 4: In the definition of x, replace E with z, and prove this does not change the semantics of x E.

04/18/23 TCS 30

Formalisation of Generalisation

Step 4: In the definition of x, replace E with z. and prove this does not change the semantics of x E.

module Main (main) where

f y = x 1 y

x z y = y : x z ( y + z)

main = print $ f 10

letrec x1=E1, ..., xi = x E, x = z.C[z] [x_i:= x z], ..., xn =En in E0

Step 5: Unfolding the occurrences of xi.

04/18/23 TCS 31

Formalisation of Generalisation

Step 5: Unfolding the occurrences of xi.

module Main (main) where

f y = x 1 y

x z y = y : x z ( y + z)

main = print $ x 1 10

letrec x1=E1 [xi:= x E] , ..., xi = x E, x = z.C[z] [xi:= x z], ..., xn =En [xi:= x E] in E0 [xi:= x E]

Step 6: Remove the definition of xi.

04/18/23 TCS 32

Formalisation of Generalisation

Step 6: Remove the definition of xi.

module Main (main) where

x z y = y : x z ( y + z)

main = print $ x 1 10

letrec x1=E1 [xi:= x E] , ..., x = z.C[z] [xi:= x z], ..., xn =En [xi:= x E] in E0 [xi:= x E]

Step 7: Rename x to xi and simplify the substitution.

04/18/23 TCS 33

Formalisation of Generalisation

module Main (main) where

f z y = y : f z ( y + z)

main = print $ f 1 10

letrec x1=E1 [xi:= x E] [x:=xi] , ..., x = z.C[z] [xi:= x z] [x:=xi], ..., xn =En [xi:= x E] [x:=xi] in E0 [xi:= x E] [x:=xi]

letrec x1= E1 [xi := xiE], ..., xi = z.C[z][xi:=xi z], ..., xn = En [xi:= xi E] in E0 [xi:= xi E]

04/18/23 TCS 34

Formalisation of Refactorings

letrec has been extended to model the Haskell module system (M).

The move a definition from one module to another refactoring has also been formalised

using M.

04/18/23 TCS 35

Future Work Adding more refactoring to HaRe. Making use of type information. Coping with modules without source code. More interaction between HaRe and the

user. Further development of the formalisation of

refactorings. Metric-based refactoring. Support for scripting refactorings. Porting HaRe to GHC . . .

04/18/23 TCS 36

www.cs.kent.ac.uk/projects/refactor-fp/

Questions?


Recommended