Widen or narrow definition scope, with compensation (generalise/specialise)


Identity: PromoteCompensate
Category: MultiModule Naming
Classifiers: promote compensation definition
Internal cross references:
External cross references:
Language: Haskell

Description:

A definition is lifted from a where or let into the surrounding binding group. Such lifting widens the scope of the definition.


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

    table = concat . format
  

showAll :: Show a => [a] -> String
showAll = table format . map show
    where
    format :: [String] -> [String]
    format []     = ... 

table :: ([String] -> [String]) -> [String] -> String
table format = concat . format
  

General comment:

Left to right comment:

This composite refactoring is more general than Promotion as it will compensate for any free variables unbound at the outer scope by making them parameters of the lifted definition. This is the process of λ-lifting (lambda-lifting), and is accomplished by Generalisation.

Right to left comment:

This is a composite refactoring that can be realised by applying Promotion right to left, and then removing the parameters: a specialisation, in other words.

Left to right conditions:

  • 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 must be a simple binding of a function or constant, rather than a pattern binding.
  • Free variables converted to arguments must not be used polymorphically; recall that whilst it is possible to use a defined name at two different (incompatible) instances, the same is not true of an argument. Note that to enforce this constraint it is necessary to have access to type checking facilities.

Right to left conditions:

  • All uses of the binding to be moved must be within the inner scope to which the definition is being moved.
  • Free variables in the binding must not be captured when it is moved over nested scopes.
  • Moreover, there should be no definition of the name in the inner binding group (irrespective of whether or not it is used).
  • A top-level definition which is explicitly exported by the module containing it can not be demoted, no matter whether it used by other modules or not. 

Analysis required:

Static scope analysis; call graph; type checking; module analysis.