470 likes | 632 Views
Refactoring Functional Programs. Simon Thompson with Huiqing Li Claus Reinke www.cs.kent.ac.uk/projects/refactor-fp. Session 1 . Refactoring. Refactoring means changing the design or structure of a program … without changing its behaviour. Modify. Refactor.
E N D
Refactoring Functional Programs Simon Thompson with Huiqing Li Claus Reinke www.cs.kent.ac.uk/projects/refactor-fp
Refactoring • Refactoring means changing the design or structure of a program … without changing its behaviour. Modify Refactor
Splitting a function • module Split where • f :: [String] -> [String] -> String • f ys = foldr (++) [] [ y++"\n" | y <- ys ]
Splitting a function • module Split where • f :: [String] -> [String] -> String • f ys = foldr (++) [] [ y++"\n" | y <- ys ]
Splitting a function • module Split where • f :: [String] -> [String] -> String • f ys = join [y ++ "\n" | y <- ys] • where • join = foldr (++) []
Splitting a function • module Split where • f :: [String] -> [String] -> String • f ys = join [y ++ "\n" | y <- ys] • where • join = foldr (++) []
Splitting a function • module Split where • f :: [String] -> [String] -> String • f ys = join addNL • where • join zs = foldr (++) [] zs • addNL = [y ++ "\n" | y <- ys]
Splitting a function • module Split where • f :: [String] -> [String] -> String • f ys = join addNL • where • join zs = foldr (++) [] zs • addNL = [y ++ "\n" | y <- ys]
Splitting a function • module Split where • f :: [String] -> [String] -> String • f ys = join (addNL ys) • where • join zs = foldr (++) [] zs • addNL ys = [y ++ "\n" | y <- ys]
Splitting a function • module Split where • f :: [String] -> [String] -> String • f ys = join (addNL ys) • where • join zs = foldr (++) [] zs • addNL ys = [y ++ "\n" | y <- ys]
Splitting a function • module Split where • f :: [String] -> [String] -> String • f ys = join (addNL ys) • join zs = foldr (++) [] zs • addNL ys = [y ++ "\n" | y <- ys]
Generalisation f 9 + 37 f h x = … f 9 + 37 … e = h 37 + 12
Generalisation f 9 + 37 h y x = … y … e = h (f 9 + 37) 37 + 12
Session 1 • Potted history of refactoring. • Refactoring and design. • Example refactorings … what do we learn? • Demonstration of the HaRe tool for Haskell. • A practical exercise.
A little bit of history … • Floyd, 1978 Turing Award Lecture: encourages reflective revision. • Griswold: Automated assistance for (LISP) program restructuring. • Opdyke: Refactoring OO Frameworks. • Fowler et al: Refactoring: Improving the Design of Existing Code.
Refactoring in OO • Smalltalk refactoring browser … relies heavily on reflection. • Built into a number of IDEs: Eclipse, … • Refactor and test … major way of ensuring correctness of refactorings … • … others require heavyweight static analysis. • Link with design …
Design • Structure of the program? • Modules, types, interfaces … • Artefact? • UML diagrams of various kinds … • … with accompanying constraints. • Model Driven Architecture • Design patterns? • The problem of consistency: design vscode.
Designing functional programs • No evidence of an appetite for separate modelling languages … • No established terminology of patterns … • … it’s all in the code.
Development • Development of functional programs is spiral … • … from a working base, extend, refactor and elaborate. • Design emerges.
Soft Ware • There’s no single correct design … • … different options for different situations. • Maintain flexibility as the system evolves.
Refactoring functionalprograms • Semantics: can articulate preconditions and verify transformations. • Absence of side effects makes big changes predictable and verifiable … unlike OO. • Language support: expressive type system; abstraction mechanisms: higher order functions, classes, …
f x y = … Name may be too specific, if the function is a candidate for reuse. findMaxVolume x y = … Make the specific purpose of the function clearer. Rename Scope: just change occurrences of thisf. Modules: change f(and M.f)everywhere.
f x y = … h … where h = … Hide a function which is clearly subsidiary to f; clear up the namespace. f x y = … (h y) … h y = … Makes h accessible to the other functions in the module and beyond. Lift / demote Free variables: which parameters of f are used in h? Need h not to be defined at the top level, … , Type of h will generally change … DMR.
Lessons from these examples • Ensuring correctness requires knowledge of: • Lexical structure of programs • Abstract syntax • Binding structure • Type system • Module system
Lessons from these examples • Changes are not limited to a single point or even a single module: diffuse and bureaucratic … • Most refactorings bidirectional … • … unlike traditional program transformation.
Visualising the effect Estimating the effect of a refactoring. Work by Chris Ryder
Program transformations • Operational semantics reduction to normal form • Program optimisationsource-to-source transformations to get more efficient code • Program derivationcalculating efficient code from obviously correct specifications • Refactoringtransforming code structure • Related themes, with substantial overlap, and common theory, but with different intentions.
Conditions: renaming f to g • “No change to the binding structure” • No two definitions of g at the same level. • No capture ofg. • No capture byg.
h x = … h … f … g … where g y = … f x = … h x = … h … g … g … where g y = … g x = … Capture of renamed identifier
h x = … h … f … g … where f y = … f … g … g x = … h x = … h … g … g … where g y = … g … g … g x = … Capture by renamed identifier
Refactoring by hand? • By hand = in a text editor • Tedious • Error-prone • Implementing the transformation … • … and the conditions. • Depends on compiler for type checking, … • … plus extensive testing.
Machine support invaluable • Reliable • Low cost of do / undo, even for large refactorings. • Increased effectiveness … and creativity.
The refactorings in HaRe Move def between modules Delete/add to exports Clean imports Make imports explicit data type to ADT Short-cut, warm fusion All module aware • Rename • Delete • Lift / Demote • Introduce definition • Remove definition • Unfold • Generalise • Add/remove parameters
Practical exercise • A practical exercise in reflective programming and design. • Work together in groups, preferably pairs.
Two roles • The writer writes design or types the program. • The logger keeps a log of the process: • Rationale for design decisions. • Refactorings in the design or the coding • Purpose, effect, extent. • Regularly swap roles. • Better understand refactoring in practice.
Context • ASCII log files plus program(s) … conclusions to go on the web. • Mail to sjt@kent.ac.uk • To reach a consensus on which refactorings are most useful and commonly used. • Document. • Implement. • Evaluate API.
What? • Any project of your own choice, perhaps building on other courses at AFP04. • Alternatively, a minesweeper program.
Minesweeper • Mines distributed in a grid: find and mark all the mines. • On revealing a square, lose if it’s occupied, if not see # adjacent. • If # is zero, clear connected region. • Can also unmark.
Minesweeper extensions • Add deduction: play all the guaranteed moves … • … or probability: reveal the square which is least likely to explode. • Show the deductions: how large support set for each deduction?
Minesweeper extensions • Add a GUI … • … or animation. • Allow backtracking?