refactoring haskell programs huiqing li computing lab, university of kent
Post on 20-Dec-2015
214 views
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 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 . . .