Download presentation
Presentation is loading. Please wait.
1
The 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/
2
29/06/2015LDTA 20052 Outline Refactoring HaRe: The Haskell Refactorer HaRe Demo The HaRe API API Demo Conclusion and Future Work
3
29/06/2015LDTA 20053 Refactoring 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.
4
29/06/2015LDTA 20054 HaRe – The Haskell Refactorer A tool for refactoring Haskell 98 programs. Full Haskell 98 coverage. Driving concerns: usability and extensibility. Implemented in Haskell, using Programatica’s frontends and Strafunski’s generic traversals. Integrated with the two program editors: (X)Emacs and Vim. Preserves both comments and layout style of the source.
5
29/06/2015LDTA 20055 Refactorings Implemented in HaRe Structural Refactorings Generalise a definition e.g. 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 h y = g y h y = g 1 y
6
29/06/2015LDTA 20056 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
7
29/06/2015LDTA 20057 Refactorings 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 h y = g y g x = x : ( g ( x + 1)) h y = g y
8
29/06/2015LDTA 20058 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
9
29/06/2015LDTA 20059 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. Add field labels Add discriminators Add constructors Remove (nested) pattern Create ADT interface.
10
29/06/2015LDTA 200510 Demonstration of HaRe, hosted in Emacs HaRe Demo
11
29/06/2015LDTA 200511 module Tree where data Tree a = Leaf a | Node a (Tree a) (Tree a) flatten :: Tree a -> [a] flatten (Leaf x ) = [x] flatten (Node x l r ) = x : (flatten l ++ flatten r) From concrete data type to ADT
12
29/06/2015LDTA 200512 module Tree where data Tree a = Leaf {leaf1 :: a} | Node {node1 :: a, node2 :: Tree a, node3 :: Tree a} flatten :: Tree a -> [a] flatten (Leaf x ) = [x] flatten (Node x l r ) = x : (flatten l ++ flatten r) From concrete data type to ADT
13
29/06/2015LDTA 200513 module Tree where data Tree a = Leaf {leaf1 :: a} | Node {node1 :: a, node2 :: Tree a, node3 :: Tree a} isLeaf :: (Tree a) -> Bool isLeaf (Leaf _) = True isLeaf _ = False isNode :: (Tree a) -> Bool isNode (Node _ _ _) = True isNode _ = False flatten :: Tree a -> [a] flatten (Leaf x ) = [x] flatten (Node x l r ) = x : (flatten l ++ flatten r) From concrete data type to ADT
14
29/06/2015LDTA 200514 module Tree where data Tree a = Leaf {leaf1 :: a} | Node {node1 :: a, node2 :: Tree a, node3 :: Tree a} mkLeaf :: a -> Tree a mkLeaf = Leaf mkNode :: a -> (Tree a) -> (Tree a) -> Tree a mkNode = Node isLeaf :: (Tree a) -> Bool isLeaf (Leaf _) = True isLeaf _ = False isNode :: (Tree a) -> Bool isNode (Node _ _ _) = True isNode _ = False flatten :: Tree a -> [a] flatten (Leaf x ) = [x] flatten (Node x l r ) = x : (flatten l ++ flatten r) From concrete data type to ADT
15
29/06/2015LDTA 200515 module Tree where data Tree a = Leaf {leaf1 :: a} | Node {node1 :: a, node2 :: Tree a, node3 :: Tree a} mkLeaf :: a -> Tree a mkLeaf = Leaf mkNode :: a -> (Tree a) -> (Tree a) -> Tree a mkNode = Node isLeaf :: (Tree a) -> Bool isLeaf (Leaf _) = True isLeaf _ = False isNode :: (Tree a) -> Bool isNode (Node _ _ _) = True isNode _ = False flatten :: Tree a -> [a] flatten p |isLeaf p = [(leaf1 p)] flatten p |isNode p = (node1 p) : (flatten (node2 p) ++ flatten (node3 p)) From concrete data type to ADT
16
29/06/2015LDTA 200516 module Tree (Tree,flatten,isLeaf,isNode,leaf1,mkLeaf,mkNode,node1,node2,node3) where data Tree a = Leaf {leaf1 :: a} | Node {node1 :: a, node2 :: Tree a, node3 :: Tree a} mkLeaf :: a -> Tree a mkLeaf = Leaf mkNode :: a -> (Tree a) -> (Tree a) -> Tree a mkNode = Node isLeaf :: (Tree a) -> Bool isLeaf (Leaf _) = True isLeaf _ = False isNode :: (Tree a) -> Bool isNode (Node _ _ _) = True isNode _ = False flatten :: Tree a -> [a] flatten p |isLeaf p = [(leaf1 p)] flatten p |isNode p = (node1 p) : (flatten (node2 p) ++ flatten (node3 p)) From concrete data type to ADT
17
29/06/2015LDTA 200517 --- 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 Generalise a definition
18
29/06/2015LDTA 200518 --- 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 Generalise a definition
19
29/06/2015LDTA 200519 --- 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 Move a definition to another module
20
29/06/2015LDTA 200520 --- 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 Clean imports
21
29/06/2015LDTA 200521 The HaRe API A collection of functions for program analysis and transformation extracted from the HaRe. Hidden layout and comment preservation in program transformation functions. Programatica’s abstract syntax for Haskell 98 + Strafunski’s library for AST traversals + HaRe’s API make implementing primitive refactorings or general program transformations much easier.
22
29/06/2015LDTA 200522 The 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, …
23
29/06/2015LDTA 200523 API 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.
24
29/06/2015LDTA 200524 API Demo -- swap the first two arguments of a function swapArgs fileName row col = do (inscps, exps, mod, ts)<-parseSourceFile fileName -- from text to program let pnt =locToPNT fileName row col mod if isFunPNT pnt mod then -- deal with the current module do r<-applyRefac (doSwap pnt) (Just (mod, ts)) fileName if isExported pnt exps then -- deal with the client modules. do rs <- applyRefacToClientMods (doSwap pnt) fileName writeRefactoredFiles False (r:rs) else writeRefactoredFiles False [r] else error "\nInvalid cursor position!" -- more code to follow
25
29/06/2015LDTA 200525 API 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 (p1:p2:ps) -> do pats'<-swap p1 p2 pats return (HsMatch loc fun pats' rhs ds) _ -> error "Insufficient arguments to swap." inMatch m = return m inExp exp@((Exp (HsApp (Exp (HsApp e e1)) e2))::HsExpP) | expToPNT e == pnt = swap e1 e2 exp inExp e = return e
26
29/06/2015LDTA 200526 API Demo inDecl (decl@(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]
27
29/06/2015LDTA 200527 Demonstration of the swap refactoring API Demo
28
29/06/2015LDTA 200528 -- Test3.hs module Test3 where sumLength:: String -> [Int]-> Int sumLength x y = length x + length y -- Test4.hs module Test4 where import Test3 test3 = sumLength "abc" [1,2,3] Swap arguments
29
29/06/2015LDTA 200529 -- Test3.hs module Test3 where sumLength:: [Int] -> String-> Int sumLength y x = length x + length y -- Test4.hs module Test4 where import Test3 test3 = sumLength [1,2,3] "abc“ Swap arguments
30
29/06/2015LDTA 200530 Conclusion 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.
31
29/06/2015LDTA 200531 www.cs.kent.ac.uk/projects/refactor-fp/
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.