Refactoring Functional Programs Huiqing Li Claus Reinke Simon Thompson Computing Lab, University of Kent www.cs.kent.ac.uk/projects/refactor-fp/

Slides:



Advertisements
Similar presentations
Testing Relational Database
Advertisements

TinyOS Tutorial, Part I Phil Levis et al. MobiSys 2003.
WS Choreography v.0-1 Overview This is work-in-progress David Burdett, Commerce One 18 June 2003.
28 July Doors Creating Time Zones. 28 July What is a Time Zone? A designated period of time in which access can be granted to a secure area.
Algorithms and Data Structures Lecture III
CS 11 C track: lecture 7 Last week: structs, typedef, linked lists This week: hash tables more on the C preprocessor extern const.
SWCAP Budgeting July 30, 2003.
HaRe The Haskell Refactorer Huiqing Li Claus Reinke Simon Thompson Computing Lab, University of Kent
Tool Support for Refactoring Functional Programs Huiqing Li Claus Reinke Simon Thompson Computing Lab, University of Kent
Huiqing Li Claus Reinke Simon Thompson Computing Lab, University of Kent Refactoring Functional Programs.
Introduction to Compilation of Functional Languages Wanhe Zhang Computing and Software Department McMaster University 16 th, March, 2004.
Huiqing Li Claus Reinke Simon Thompson Computing Lab, University of Kent Refactoring Functional Programs.
Refactoring Functional Programs Simon Thompson with Huiqing Li Claus Reinke
Progress on ‘HaRe: The Haskell Refactorer’ Huiqing Li, Claus Reinke, Simon Thompson Computing Laboratory, University of Kent Refactoring is the process.
Using XSLT for Interoperability: DOE and The Traveling Domain Experiment Monday 20 th of October, 2003 Antoine Isaac, Raphaël Troncy and Véronique Malaisé.
Kathleen Fisher cs242 Reading: “A history of Haskell: Being lazy with class”,A history of Haskell: Being lazy with class Section 6.4 and Section 7 “Monads.
Control-Flow Graphs & Dataflow Analysis CS153: Compilers Greg Morrisett.
1 Mooly Sagiv and Greta Yorsh School of Computer Science Tel-Aviv University Modern Compiler Design.
8. Introduction to Denotational Semantics. © O. Nierstrasz PS — Denotational Semantics 8.2 Roadmap Overview:  Syntax and Semantics  Semantics of Expressions.
CSE341: Programming Languages Lecture 16 Datatype-Style Programming With Lists or Structs Dan Grossman Winter 2013.
Getting started with ML ML is a functional programming language. ML is statically typed: The types of literals, values, expressions and functions in a.
Refactoring Functional Programs Claus Reinke Simon Thompson TCS Seminar, 1 October 2001.
Clean code. Motivation Total cost = the cost of developing + maintenance cost Maintenance cost = cost of understanding + cost of changes + cost of testing.
The Formalisation of Haskell Refactorings Huiqing Li Simon Thompson Computing Lab, University of Kent
Introduction to ML Last time: Basics: integers, Booleans, tuples,... simple functions introduction to data types This time, we continue writing an evaluator.
Refactoring Haskell Programs Huiqing Li Computing Lab, University of Kent
WRT 2007 Refactoring Functional Programs Huiqing Li Simon Thompson Computing Lab Chris Brown Claus Reinke University of Kent.
Chapter 3 Program translation1 Chapt. 3 Language Translation Syntax and Semantics Translation phases Formal translation models.
The Haskell Refactorer, HaRe, and its API Huiqing Li Claus Reinke Simon Thompson Computing Lab, University of Kent
About the Presentations The presentations cover the objectives found in the opening of each chapter. All chapter objectives are listed in the beginning.
Guide To UNIX Using Linux Third Edition
Generative Programming. Generic vs Generative Generic Programming focuses on representing families of domain concepts Generic Programming focuses on representing.
Refactoring Functional Programs Huiqing Li Claus Reinke Simon Thompson Computing Lab, University of Kent.
CSC 8310 Programming Languages Meeting 2 September 2/3, 2014.
CASE Tools And Their Effect On Software Quality Peter Geddis – pxg07u.
Starting Chapter 4 Starting. 1 Course Outline* Covered in first half until Dr. Li takes over. JAVA and OO: Review what is Object Oriented Programming.
Classes Mark Hennessy Dept. Computer Science NUI Maynooth C++ Workshop 18 th – 22 nd Spetember 2006.
REFACTORING Lecture 4. Definition Refactoring is a process of changing the internal structure of the program, not affecting its external behavior and.
PrasadCS7761 Haskell Data Types/ADT/Modules Type/Class Hierarchy Lazy Functional Language.
Mathematical Modeling and Formal Specification Languages CIS 376 Bruce R. Maxim UM-Dearborn.
07 Coding Conventions. 2 Demonstrate Developing Local Variables Describe Separating Public and Private Members during Declaration Explore Using System.exit.
Supported by ELTE IKKK, Ericsson Hungary, in cooperation with University of Kent Erlang refactoring with relational database Anikó Víg and Tamás Nagy Supervisors:
Generative Programming. Automated Assembly Lines.
Cohesion and Coupling CS 4311
COMPILERS Symbol Tables hussein suleman uct csc3003s 2007.
1 Compiler Construction (CS-636) Muhammad Bilal Bashir UIIT, Rawalpindi.
Unit-1 Introduction Prepared by: Prof. Harish I Rathod
Supported by ELTE IKKK, Ericsson Hungary, in cooperation with University of Kent Erlang refactoring with relational database Anikó Víg and Tamás Nagy Supervisors:
Python Functions.
Introducing Python CS 4320, SPRING Lexical Structure Two aspects of Python syntax may be challenging to Java programmers Indenting ◦Indenting is.
1 CSC/ECE 517 Fall 2010 Lec. 3 Overview of Eclipse Lectures Lecture 2 “Lecture 0” Lecture 3 1.Overview 2.Installing and Running 3.Building and Running.
Refactoring 2. Admin Blackboard Quiz Acknowledgements Material in this presentation was drawn from Martin Fowler, Refactoring: Improving the Design of.
Programming Languages and Design Lecture 3 Semantic Specifications of Programming Languages Instructor: Li Ma Department of Computer Science Texas Southern.
Object Oriented Programming
Scalable Clone Detection and Elimination for Erlang Programs Huiqing Li, Simon Thompson University of Kent Canterbury, UK.
SEG 4110 – Advanced Software Design and Reengineering Topic T Introduction to Refactoring.
1 Classes II Chapter 7 2 Introduction Continued study of –classes –data abstraction Prepare for operator overloading in next chapter Work with strings.
Advanced Functional Programming Tim Sheard 1 Lecture 17 Advanced Functional Programming Tim Sheard Oregon Graduate Institute of Science & Technology Lecture:
Refactoring1 Improving the structure of existing code.
Refactoring Agile Development Project. Lecture roadmap Refactoring Some issues to address when coding.
PROGRAMMING PRE- AND POSTCONDITIONS, INVARIANTS AND METHOD CONTRACTS B MODULE 2: SOFTWARE SYSTEMS 13 NOVEMBER 2013.
Overview of Compilation Prepared by Manuel E. Bermúdez, Ph.D. Associate Professor University of Florida Programming Language Principles Lecture 2.
Chapter 1: Preliminaries Lecture # 2. Chapter 1: Preliminaries Reasons for Studying Concepts of Programming Languages Programming Domains Language Evaluation.
Lecture 9 Symbol Table and Attributed Grammars
Software Testing.
A lightening tour in 45 minutes
Lecture 15 (Notes by P. N. Hilfinger and R. Bodik)
Programming Languages 2nd edition Tucker and Noonan
Records and Type Classes
Records and Type Classes
Presentation transcript:

Refactoring Functional Programs Huiqing Li Claus Reinke Simon Thompson Computing Lab, University of Kent

SBLP Refactoring Refactoring means changing the design of program … … without changing its behaviour. Refactoring comes in many forms micro refactoring as a part of program development major refactoring as a preliminary to revision as a part of debugging, … As programmers, we do it all the time.

SBLP Refactoring functional programs What is possible for functional programs? What is different about functional programs? Building a usable tool vs. … … building a tool that will be used. Reflection on language design. Experience, demonstration, next steps. Haskell as a medium, but wider applicability.

SBLP Not just programming Paper or presentation moving sections about; amalgamate sections; move inline code to a figure; animation; … Proof introduce lemma; remove, amalgamate hypotheses, … Program the topic of the lecture

SBLP Overview of the talk Example refactorings Refactoring functional programs Generalities Tooling: demo, rationale, design. Catalogue of refactorings Larger-scale examples … and a case study Conclusions

SBLP Rename 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. Needs scope information: just change this f and not all f s (e.g. local definitions or variables).

SBLP Lift / demote 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?). Needs free variable information: which of the parameters of f is used in the definition of h ? Need h not to be defined at the top level, …, DMR.

SBLP Introduce and use a type def n f :: Int -> Char g :: Int -> Int …  Reuse supported (a synonym is transparent, but can be misleading). type Length = Int f :: Length -> Char g :: Int -> Length  Clearer specification of the purpose of f, g. (Morally) can only apply to lengths. Avoid name clashes Problem with instance declarations (Haskell specific).

SBLP Introduce and use branded type f :: Int -> Char g :: Int -> Int …  Reuse supported, but lose the clarity of specification. data Length = Length {length::Int} f :: Length -> Char g :: Int -> Length  Can only apply to lengths. Needs function call information: where are (these definitions of) f and g called? Change the calls of f … and the call sites of g. Choice of data and newtype (Haskell specific).

SBLP Lessons from the first examples Changes are not limited to a single point or even a single module: diffuse and bureaucratic … … unlike traditional program transformation. Many refactorings bidirectional … … there is no single correct design.

SBLP Refactoring functional programs Semantics: can articulate preconditions and … … verify transformations. Absence of side effects makes big changes predictable and verifiable … … unlike OO. XP is second nature to a functional programmer. Language support: expressive type system, abstraction mechanisms, HOFs, …

SBLP Composing refactorings Interesting refactorings can be built from simple components … … each of which looks trivial in its own right. A set of examples … … which we have implemented.

SBLP Example program showAll :: Show a => [a] -> String showAll = table. map show where format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table :: [String] -> String table = concat. format

SBLP Examples Lift definitions from local to global Demote a definition before lifting its container Lift a definition with dependencies

SBLP Example 1 showAll :: Show a => [a] -> String showAll = table. map show where format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table :: [String] -> String table = concat. format

SBLP Example 1 lift showAll :: Show a => [a] -> String showAll = table. map show where format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table :: [String] -> String table = concat. format

SBLP Example 1 showAll :: Show a => [a] -> String showAll = table. map show where table :: [String] -> String table = concat. format format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs

SBLP Example 1 lift showAll :: Show a => [a] -> String showAll = table. map show where table :: [String] -> String table = concat. format format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs

SBLP Example 1 showAll :: Show a => [a] -> String showAll = table. map show table :: [String] -> String table = concat. format format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs

SBLP Example 2 showAll :: Show a => [a] -> String showAll = table. map show where format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table :: [String] -> String table = concat. format

SBLP Example 2 demote showAll :: Show a => [a] -> String showAll = table. map show where format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table :: [String] -> String table = concat. format

SBLP Example 2 showAll :: Show a => [a] -> String showAll = table. map show where table :: [String] -> String table = concat. format where format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs

SBLP Example 2 lift showAll :: Show a => [a] -> String showAll = table. map show where table :: [String] -> String table = concat. format where format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs

SBLP Example 2 showAll :: Show a => [a] -> String showAll = table. map show table :: [String] -> String table = concat. format where format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs

SBLP Example 2 lift showAll :: Show a => [a] -> String showAll = table. map show table :: [String] -> String table = concat. format where format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs

SBLP Example 2 showAll :: Show a => [a] -> String showAll = table. map show table :: [String] -> String table = concat. format format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs

SBLP Example 3 showAll :: Show a => [a] -> String showAll = table. map show where format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table :: [String] -> String table = concat. format

SBLP Example 3 lift with dependencies showAll :: Show a => [a] -> String showAll = table. map show where format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table :: [String] -> String table = concat. format

SBLP Example 3 showAll :: Show a => [a] -> String showAll = table format. map show where format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table :: ([String] -> [String]) -> [String] -> String table format = concat. format

SBLP Example 3 rename showAll :: Show a => [a] -> String showAll = table format. map show where format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table :: ([String] -> [String]) -> [String] -> String table format = concat. format

SBLP Example 3 showAll :: Show a => [a] -> String showAll = table format. map show where format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table :: ([String] -> [String]) -> [String] -> String table fmt = concat. fmt

SBLP Example 3 lift showAll :: Show a => [a] -> String showAll = table format. map show where format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table :: ([String] -> [String]) -> [String] -> String table fmt = concat. fmt

SBLP Example 3 showAll :: Show a => [a] -> String showAll = table format. map show format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table :: ([String] -> [String]) -> [String] -> String table fmt = concat. fmt

SBLP Example 3 unfold/inline showAll :: Show a => [a] -> String showAll = table format. map show format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table :: ([String] -> [String]) -> [String] -> String table fmt = concat. fmt

SBLP Example 3 showAll :: Show a => [a] -> String showAll = (concat. format). map show format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table :: ([String] -> [String]) -> [String] -> String table fmt = concat. fmt

SBLP Example 3 delete showAll :: Show a => [a] -> String showAll = (concat. format). map show format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table :: ([String] -> [String]) -> [String] -> String table fmt = concat. fmt

SBLP Example 3 showAll :: Show a => [a] -> String showAll = (concat. format). map show format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs

SBLP Example 3 new definition showAll :: Show a => [a] -> String showAll = (concat. format). map show format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table Name?

SBLP Example 3 showAll :: Show a => [a] -> String showAll = table. map show format :: [String] -> [String] format [] = [] format [x] = [x] format (x:xs) = (x ++ "\n") : format xs table :: [String] -> String table = concat. format

SBLP Beyond the text editor All the refactorings can – in principle – be implemented using a text editor, but this is tedious, error-prone, difficult to reverse, … With machine support refactoring becomes low-cost: easy to do and to undo, reliable, a full part of the programmer's repertoire.

SBLP Information needed Syntax: replace the function called sq, not the variable sq …… parse tree. Static semantics: replace this function sq, not all the sq functions …… scope information. Module information: what is the traffic between this module and its clients …… call graph. Type information: replace this identifier when it is used at this type …… type annotations.

SBLP Machine support invaluable Current practice: editor + type checker (+ tests). Our project: automated support for a repertoire of refactorings … … integrated into the existing development process: tools such as vim and emacs. Demonstration of the tool, hosted in vim.

SBLP Proof of concept … To show proof of concept it is enough to: build a stand-alone tool, work with a subset of the language, ‘pretty print’ the refactored source code in a standard format.

SBLP … or a useful tool? To make a tool that will be used we must: integrate with existing program development tools: the program editors emacs and vim: only add to their capabilities. work with the complete Haskell 98 language, preserve the formatting and comments in the refactored source code.

SBLP Consequences To achieve this we chose to: build a tool that can interoperate with emacs, vim, … yet act separately. leverage existing libraries for processing Haskell 98, for tree transformation, yet … … modify them as little as possible. be as portable as possible, in the Haskell space.

SBLP The Haskell background Libraries parser:many type checker:few tree transformations:few Difficulties Haskell98 vs. Haskell extensions. Libraries: proof of concept vs. distributable. Source code regeneration. Real project

SBLP First steps … lifting and friends Use the Haddock parser … full Haskell given in 500 lines of data type definitions. Work by hand over the Haskell syntax: 27 cases for expressions … Code for finding free variables, for instance …

SBLP Finding free variables … 100 lines instance FreeVbls HsExp where freeVbls (HsVar v) = [v] freeVbls (HsApp f e) = freeVbls f ++ freeVbls e freeVbls (HsLambda ps e) = freeVbls e \\ concatMap paramNames ps freeVbls (HsCase exp cases) = freeVbls exp ++ concatMap freeVbls cases freeVbls (HsTuple _ es) = concatMap freeVbls es … etc.

SBLP This approach Boiler plate code … … 1000 lines for 100 lines of significant code. Error prone: significant code lost in the noise. Want to generate the boiler plate and the tree traversals … … DriFT: Winstanley, Wallace … Strafunski: Lämmel and Visser

SBLP Strafunski Strafunski allows a user to write general (read generic) tree traversing programs … … with ad hoc behaviour at particular points. Traverse through the tree accumulating free variables from component parts, except in the case of lambda abstraction, local scopes, … Strafunski allows us to work within Haskell … other options are under development.

SBLP Production tool (version 0) Programatica parser and type checker Refactor using a Strafunski engine Pretty print from the augmented Programatica syntax tree

SBLP Production tool (version 1) Programatica parser and type checker Refactor using a Strafunski engine Pretty print from the augmented Programatica syntax tree Pass lexical information to update the syntax tree and so avoid reparsing

SBLP Experience so far We can do it … but … efficiency formalising static semantics change management (CVS etc.) user interface interface to other tools problems of getting code to work different systems working together clash of instance : global problem Haskell in the large (e.g. 20 minute link time)

SBLP Clarification Implementation yields clarification. The precise way to document refactorings … … and in particular their preconditions.

SBLP Catalogue of refactorings name (a phrase) label (a word) description left-hand code right-hand code comments l to r r to l general primitive / composed cross-references internal external (Fowler) category (just one) or … … classifiers (keywords) language specific (Haskell, ML etc.) feature (lazy etc.) conditions left / right analysis required (e.g. names, types, semantic info.) which equivalence? version info date added revision number

SBLP Preconditions It is possible precisely to articulate the preconditions for successful application of the refactorings For example, in renaming, the existing binding structure must not be affected …

SBLP Preconditions: renaming f to g No binding for the new name may exist in the same binding group. f = … g = …

SBLP Preconditions: renaming f to g No binding for the new name may exist in the same binding group. g = …

SBLP f = … where g = … h = … f … Preconditions: renaming f to g No binding for the new name may intervene between the binding of the old name and any of its uses … … as the renamed identifier would be captured by the renaming.

SBLP g = … where g = … h = … g … Preconditions: renaming f to g No binding for the new name may intervene between the binding of the old name and any of its uses … … as the renamed identifier would be captured by the renaming.

SBLP Preconditions: renaming f to g Conversely, the binding to be renamed must not intervene between bindings and uses of the new name. g = … where f = … h = … g …

SBLP Preconditions: renaming f to g Conversely, the binding to be renamed must not intervene between bindings and uses of the new name. g = … where g = … h = … g …

SBLP Preconditions: lifting Widening the scope of the binding must not capture independent uses of the name in the outer scope. There should be no existing definition of the name in the outer binding group (irrespective of whether or not it is used). The binding to be promoted must not make use of bindings in the inner scope. Instead lambda lift over these; extra conds apply:

SBLP Preconditions: lifting Lambda lift over these; extra conds apply: The binding must be a simple binding of a function or constant, not a pattern. Any argument must not be used polymorphically. f = … where g (x:xs) = x h = g “test” ++ show (g [1,2,3])

SBLP Crossing the refactoring Rubicon? Martin Fowler’s ‘Rubicon’: implement ‘extract definition’ … compare with other systems. This is in our  version already … … and we’re only 1/3 of the way into the project. Productivity of functional programming. Challenge of implementing larger refactorings.

SBLP Larger-scale examples More complex examples in the functional domain; often link with data types. Dawning realisation that can some refactorings are pretty powerful. Bidirectional … no right answer.

SBLP Algebraic or abstract type? data Tr a = Leaf a | Node a (Tr a) (Tr a) Tr Leaf Node flatten :: Tr a -> [a] flatten (Leaf x) = [x] flatten (Node s t) = flatten s ++ flatten t

SBLP Algebraic or abstract type? data Tr a = Leaf a | Node a (Tr a) (Tr a) isLeaf = … isNode = … … Tr isLeaf isNode leaf left right mkLeaf mkNode flatten :: Tr a -> [a] flatten t | isleaf t = [leaf t] | isNode t = flatten (left t) ++ flatten (right t)

SBLP Algebraic or abstract type?  Pattern matching syntax is more direct … … but can achieve a considerable amount with field names. Other reasons? Simplicity (due to other refactoring steps?).  Allows changes in the implementation type without affecting the client: e.g. might memoise Problematic with a primitive type as carrier. Allows an invariant to be preserved.

SBLP Outside or inside? data Tr a = Leaf a | Node a (Tr a) (Tr a) isLeaf = … … Tr isLeaf isNode leaf left right mkLeaf mkNode flatten :: Tr a -> [a] flatten t | isleaf t = [leaf t] | isNode t = flatten (left t) ++ flatten (right t)

SBLP Outside or inside? data Tr a = Leaf a | Node a (Tr a) (Tr a) isLeaf = … … flatten = … Tr isLeaf isNode leaf left right mkLeaf mkNode flatten

SBLP Outside or inside?  If inside and the type is reimplemented, need to reimplement everything in the signature, including flatten. The more outside the better, therefore.  If inside can modify the implementation to memoise values of flatten, or to give a better implementation using the concrete type. Layered types possible: put the utilities in a privileged zone.

SBLP Replace function by constructor data Expr = Star Expr | Then Expr Expr | … plus e = Then e (Star e)  plus is just syntactic sugar; reduce the number of cases in definitions. [Character range is a better example.] data Expr = Star Expr | Plus Expr | Then Expr Expr | …  Can treat Plus differently, e.g. literals (Plus e) = literals e but require each function over Expr to have a Plus clause.

SBLP Other examples... Modify the return type of a function from T to Maybe T, Either T T' or [T]. Would be nice to have field names in Prelude types. Add an argument; (un)group arguments; reorder arguments. Move to monadic presentation: important case study. Flat or layered datatypes ( Expr : add BinOp type). Various possibilities for error handling/exceptions. … Tableau case study.

SBLP Change of user interface Refactor the existing text-based application … … so that it can have textual or graphical user interface.

SBLP Changing functionality? The aim is not to change functionality … … or at least not required functionality. What level of behaviour is visible? May change incidental properties … … cf legacy systems: preserve their essential properties but not their accidental ones.

SBLP Other uses of refactoring Understand someone else’s code … … make it your own. Understanding your own code. Preparing for major changes. etc. …

SBLP Teaching and learning design Exciting prospect of using a refactoring tool as an integral part of an elementary programming course. Learning a language: learn how you could modify the programs that you have written … … appreciate the design space, and … the features of the language.

SBLP Conclusions Refactoring + functional programming: good fit. Stresses the type system: generic traversal … Practical tool … not ‘yet another type tweak’. Leverage from available libraries … with work. We are eager to use the tool in building itself!

SBLP Understanding: semantic tableaux Take a working semantic tableau system written by an anonymous 2nd year student … … refactor to understand its behaviour. Nine stages of unequal size. Reflections afterwards. See

SBLP An example tableau  ( (A  C)  ((A  B)  C) )  ((A  B)  C) (A  C)  C AA  (A  B)  C   AB Make B True Make A and C False

SBLP v1: Name types Built-in types [Prop] [[Prop]] used for branches and tableaux respectively. Modify by adding type Branch = [Prop] type Tableau = [Branch] Change required throughout the program. Simple edit: but be aware of the order of substitutions: avoid type Branch = Branch

SBLP v2: Rename functions Existing names tableaux removeBranch remove become tableauMain removeDuplicateBranches removeBranchDuplicates and add comments clarifying the (intended) behaviour. Add test datum. Discovered some edits undone in stage 1. Use of the type checker to catch errors. test will be useful later?

SBLP v3: Literate  normal script Change from literate form: Comment … > tableauMain tab > =... to -- Comment … tableauMain tab =... Editing easier: implicit assumption was that it was a normal script. Could make the switch completely automatic?

SBLP v4: Modify function definitions From explicit recursion: displayBranch :: [Prop] -> String displayBranch [] = [] displayBranch (x:xs) = (show x) ++ "\n" ++ displayBranch xs to displayBranch :: Branch -> String displayBranch = concat. map (++"\n"). map show More abstract … move somewhat away from the list representation to operations such as map and concat which could appear in the interface to any collection type. First time round added incorrect (but type correct) redefinition … only spotted at next stage. Undo, redo, merge, … ?

SBLP v5: Algorithms and types (1) removeBranchDup :: Branch -> Branch removeBranchDup [] = [] removeBranchDup (x:xs) | x == findProp x xs = [] ++ removeBranchDup xs | otherwise = [x] ++ removeBranchDup xs findProp :: Prop -> Branch -> Prop findProp z [] = FALSE findProp z (x:xs) | z == x = x | otherwise = findProp z xs

SBLP v5: Algorithms and types (2) removeBranchDup :: Branch -> Branch removeBranchDup [] = [] removeBranchDup (x:xs) | findProp x xs = [] ++ removeBranchDup xs | otherwise = [x] ++ removeBranchDup xs findProp :: Prop -> Branch -> Bool findProp z [] = False findProp z (x:xs) | z == x = True | otherwise = findProp z xs

SBLP v5: Algorithms and types (3) removeBranchDup :: Branch -> Branch removeBranchDup = nub findProp :: Prop -> Branch -> Bool findProp = elem

SBLP v5: Algorithms and types (4) removeBranchDup :: Branch -> Branch removeBranchDup = nub Fails the test ! Two duplicate branches output, with different ordering of elements. The algorithm used is the 'other' nub algorithm, nubVar : nub [1,2,0,2,1] = [1,2,0] nubVar [1,2,0,2,1] = [0,2,1] The code is dependent on using lists in a particular order to represent sets.

SBLP v6: Library function to module Add the definition: nubVar = … to the module ListAux.hs and replace the definition by import ListAux Editing easier: implicit assumption was that it was a normal script. Could make the switch completely automatic?

SBLP v7: Housekeeping Renamings: including foo and bar and contra (becomes notContra ). An instance of filter, looseEmptyLists is defined using filter, and subsequently inlined. Put auxiliary function into a where clause. Generally cleans up the script for the next onslaught.

SBLP v8: Algorithm (2) splitXXX removeXXX solveXXX are present for each of nine rules. The algorithm applies rules in a prescribed order, using an integer value to pass information between functions. Aim: generic versions of split remove solve Have to change order of rule application … … which has a further effect on duplicates. Add map sort to top level pipeline prior to duplicate removal.

SBLP v9: Replace lists by sets. Wholesale replacement of lists by a Set library. mapmapSet foldrfoldSet (careful!) filterfilterSet The library exposes the representation: pick, flatten. Use with discretion … further refactoring possible. Library needed to be augmented with primRecSet :: (a -> Set a -> b -> b) -> b -> Set a -> b

SBLP v9: Replace lists by sets (2) Drastic simplification: no need for explicit worries about … ordering and its effect on equality, … (removal of) duplicates. Difficult to test whilst in intermediate stages: the change in a type is all or nothing … … work with dummy definitions and the type checker. Further opportunities: … why choose one rule from a set when could apply to all elements at once? Gets away from picking on one value (and breaking the set interface).

SBLP Conclusions of the case study Heterogeneous process: some small, some large. Are all these stages strictly refactorings: some semantic changes always necessary too? Importance of type checking for hand refactoring … … and testing when any semantic changes. Undo, redo, reordering the refactorings … CVS. In this case, directional … not always the case.