Title: The Haskell Refactorer, HaRe, and its API
1The Haskell Refactorer, HaRe, and its API
- Huiqing Li
- Claus Reinke
- Simon Thompson
- Computing Lab, University of Kent
- www.cs.kent.ac.uk/projects/refactor-fp/
2Outline
- Refactoring
- HaRe The Haskell Refactorer
- HaRe Demo
- The HaRe API
- API Demo
- Conclusion and Future Work
3Refactoring
- What? Changing the structure of existing code
without changing its meaning. - Source-to-source
- Functionality-preserving
- Diffuse and bureaucratic
- Bi-directional
- Where and why? Development, maintenance,
- To make the code easier to understand and modify
- To improve code reuse, quality and productivity
- Essential part of the programming process.
4HaRe The Haskell Refactorer
- A tool for refactoring Haskell 98 programs.
- Full Haskell 98 coverage.
- Driving concerns usability and extensibility.
- Implemented in Haskell, using Programaticas
frontends and Strafunskis generic traversals. - Integrated with the two program editors (X)Emacs
and Vim. - Preserves both comments and layout style of the
source.
5Refactorings Implemented in HaRe
- Structural Refactorings
- Generalise a definition
- e.g.
module Test1 where
module Test1 where g x x (g (x 1))
g m x x ((g m) (x
m)) module Test2 where ?
module Test2 where import Test1
import Test1 h y g y
h
y g 1 y
6Refactorings 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
-
7Refactorings Implemented in HaRe
- Module Refactorings
- Move a definition from one module to another
module - e.g.
module Test1(g) where module
Test1 where g x x (g (x 1))
module Test2 where ?
module Test2 where import Test1
import Test1 h y g y
g x x ( g
( x 1))
h y g y
8Refactorings 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
9Refactorings 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. - Add field labels
- Add discriminators
- Add constructors
- Remove (nested) pattern
- Create ADT interface.
10HaRe Demo
Demonstration of HaRe, hosted in Emacs
11From concrete data type to ADT
module Tree where data Tree a Leaf a
Node a (Tree a) (Tree a) flatten Tree a -gt
a flatten (Leaf x ) x flatten (Node x l r
) x (flatten l flatten r)
12From concrete data type to ADT
module Tree where data Tree a Leaf leaf1
a Node node1 a, node2 Tree a,
node3 Tree a flatten Tree a -gt
a flatten (Leaf x ) x flatten (Node x l r
) x (flatten l flatten r)
13From concrete data type to ADT
module Tree where data Tree a Leaf leaf1
a Node node1 a, node2 Tree a,
node3 Tree a isLeaf (Tree a) -gt
Bool isLeaf (Leaf _) True isLeaf _ False
isNode (Tree a) -gt Bool isNode (Node _ _ _)
True isNode _ False flatten Tree a -gt
a flatten (Leaf x ) x flatten (Node x l r )
x (flatten l flatten r)
14From concrete data type to ADT
module Tree where data Tree a Leaf leaf1
a Node node1 a, node2 Tree a,
node3 Tree a mkLeaf a -gt Tree a mkLeaf
Leaf mkNode a -gt (Tree a) -gt (Tree a) -gt Tree
a mkNode Node isLeaf (Tree a) -gt
Bool isLeaf (Leaf _) True isLeaf _ False
isNode (Tree a) -gt Bool isNode (Node _ _ _)
True isNode _ False flatten Tree a -gt
a flatten (Leaf x ) x flatten (Node x l r )
x (flatten l flatten r)
15From concrete data type to ADT
module Tree where data Tree a Leaf leaf1
a Node node1 a, node2 Tree a,
node3 Tree a mkLeaf a -gt Tree a mkLeaf
Leaf mkNode a -gt (Tree a) -gt (Tree a) -gt
Tree a mkNode Node isLeaf (Tree a) -gt
Bool isLeaf (Leaf _) True isLeaf _ False
isNode (Tree a) -gt Bool isNode (Node _ _ _)
True isNode _ False flatten Tree a -gt
a flatten p isLeaf p (leaf1
p) flatten p isNode p (node1 p)
(flatten (node2 p) flatten (node3 p))
16From concrete data type to ADT
module Tree (Tree,flatten,isLeaf,isNode,leaf1,mkLe
af,mkNode,node1,node2,node3) where data Tree
a Leaf leaf1 a Node node1 a,
node2 Tree a, node3 Tree a mkLeaf a -gt
Tree a mkLeaf Leaf mkNode a -gt (Tree a) -gt
(Tree a) -gt Tree a mkNode Node isLeaf
(Tree a) -gt Bool isLeaf (Leaf _) True isLeaf _
False isNode (Tree a) -gt Bool isNode (Node
_ _ _) True isNode _ False flatten Tree
a -gt a flatten p isLeaf p (leaf1
p) flatten p isNode p (node1 p)
(flatten (node2 p) flatten (node3 p))
17Generalise a definition
--- Test1.hs module Test1(g) where -- a
generator g x x (g (x 1)) -- Test2.hs
module Test2 where import Test1 h y g y
18Generalise a definition
--- Test1.hs module Test1(g) where -- a
generator g m x x ((g m) (x m)) -- Test2.hs
module Test2 where import Test1 h y g 1 y
19Move a definition to another module
--- Test1.hs module Test1() where -- Test2.hs
module Test2 where import Test1 -- a
generator g m x x ((g m) (x m)) h y g 1 y
20Clean imports
--- Test1.hs module Test1() where -- Test2.hs
module Test2 where -- a generator g m x x
((g m) (x m)) h y g 1 y
21The HaRe API
- A collection of functions for program analysis
and transformation extracted from the HaRe. - Hidden layout and comment preservation in program
transformation functions. - Programaticas abstract syntax for Haskell 98
- Strafunskis library for AST traversals
- HaRes API
- make implementing primitive refactorings or
general program transformations much easier.
22The HaRe API
- Program analysis API
- Variable analysis
- Property checking
- Module interface (import and exports) analysis
- Module and files
- Program transformation API
- Add/remove/update/swap program entities (e.g.
declarations, expressions, parameters,
identifiers, etc.) - Others
- Parsing/writing
- Name generators, from textual to AST syntax
phrase,
23API Demo
- Example refactoring Swap the first two arguments
of a function, say foo. This affects - The formal parameters of foo.
- The arguments at the use-sites of foo throughout
the program (could be a multi-module program). - The type signature.
-
24API Demo
-- swap the first two arguments of a
function swapArgs fileName row col do (inscps,
exps, mod, ts)lt-parseSourceFile fileName
-- from text to program
let pnt locToPNT
fileName row col mod
if isFunPNT pnt mod
then -- deal with the current module
do rlt-applyRefac (doSwap pnt) (Just
(mod, ts)) fileName if
isExported pnt exps then
-- deal with the client modules.
do rs lt- applyRefacToClientMo
ds (doSwap pnt) fileName
writeRefactoredFiles False (rrs)
else
writeRefactoredFiles False r else
error "\nInvalid cursor position!"
-- more code to follow
25API Demo
--- Inside a module doSwap pnt applyTP
(full_buTP (idTP adhocTP inMatch
adhocTP inExp
adhocTP
inDecl)) where inMatch ((HsMatch loc
fun pats rhs ds)HsMatchP) fun pnt
case pats of (p1p2ps) -gt
do pats'lt-swap p1 p2 pats
return (HsMatch loc fun pats' rhs
ds) _ -gt error
"Insufficient arguments to swap." inMatch m
return m inExp exp_at_((Exp (HsApp (Exp
(HsApp e e1)) e2))HsExpP) expToPNT e
pnt swap e1 e2 exp inExp e
return e
26API Demo
inDecl (decl_at_(Dec (HsTypeSig loc is c
tp))HsDeclP) isTypeSigOf pnt decl
if length is 1 then do let ts
tyFunToList tp swap
(ts!!0) (ts!!1) ts -- assume no
type synonym is used. else error "This
type signature defines the type of more than one
identifiers." inDecl d return d tyFunToList
(Typ (HsTyFun t1 t2)) t1(tyFunToList t2)
tyFunToList t t
27API Demo
Demonstration of the swap refactoring
28Swap arguments
-- Test3.hs module Test3 where sumLength
String -gt Int-gt Int sumLength x y length x
length y -- Test4.hs module Test4 where
import Test3 test3 sumLength "abc" 1,2,3
29Swap arguments
-- Test3.hs module Test3 where sumLength
Int -gt String-gt Int sumLength y x length x
length y -- Test4.hs module Test4 where
import Test3 test3 sumLength 1,2,3 "abc
30Conclusion and Future Work
- The API is relatively low-level, but essential
for implementing program transformations. - Program appearance preservation hidden in the
API. - Together with Strafunski, the API allows to write
concise source-to-source program transformations
and their side-conditions. - A framework for exploring your program
transformation ideas. - In the future
- Complete and improve the current API.
- Look for some higher-level API.
31www.cs.kent.ac.uk/projects/refactor-fp/