Presentation is loading. Please wait.

Presentation is loading. Please wait.

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/

Similar presentations


Presentation on theme: "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/"— Presentation transcript:

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/


Download ppt "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/"

Similar presentations


Ads by Google