16 research outputs found
Partially-Static Data as Free Extension of Algebras
Partially-static data structures are a well-known technique for improving binding times. However, they are often defined in an ad-hoc manner, without a unifying framework to ensure full use of the equations associated with each operation. We present a foundational view of partially-static data structures as free extensions of algebras for suitable equational theories, i.e. the coproduct of an algebra and a free algebra in the category of algebras and their homomorphisms. By precalculating these free extensions, we construct a high-level library of partially-static data representations for common algebraic structures. We demonstrate our library with common use-cases from the literature: string and list manipulation, linear algebra, and numerical simplification.Supported by the European Research Council grant âevents causality and symmetry Ă the next- generation semanticsâ; the Engineering and Physical Sciences Research Council grant EP/N007387/1 âQuantum computation as a programming languageâ, and a Balliol College Oxford Career Development Fellowshi
Catamorphism-based program transformations for non-strict functional languages
In functional languages intermediate data structures are often used as glue to connect
separate parts of a program together. These intermediate data structures are useful because
they allow modularity, but they are also a cause of inefficiency: each element need to be
allocated, to be examined, and to be deallocated.
Warm fusion is a program transformation technique which aims to eliminate intermediate
data structures. Functions in a program are first transformed into the so called build-cata
form, then fused via a one-step rewrite rule, the cata-build rule. In the process of the
transformation to build-cata form we attempt to replace explicit recursion with a fixed
pattern of recursion (catamorphism).
We analyse in detail the problem of removing - possibly mutually recursive sets of -
polynomial datatypes.
Wehave implemented the warm fusion method in the Glasgow Haskell Compiler, which has
allowed practical feedback. One important conclusion is that catamorphisms and fusion
in general deserve a more prominent role in the compilation process. We give a detailed
measurement of our implementation on a suite of real application programs
Transformation of functional programs for identification of parallel skeletons
Hardware is becoming increasingly parallel. Thus, it is essential to identify and exploit inherent parallelism in a given program to effectively utilise the computing power available. However, parallel programming is tedious and error-prone when done by hand, and is very difficult for a compiler to do automatically to the desired level. One possible approach to parallel programming is to use transformation techniques to automatically identify and explicitly specify parallel computations in a given program using parallelisable algorithmic skeletons.
Current existing methods for systematic derivation of parallel programs or parallel skeleton identification allow automation. However, they place constraints on the programs to which they are applicable, require manual derivation of operators with specific properties for parallel execution, or allow the use of inefficient intermediate data structures
in the parallel programs.
In this thesis, we present a program transformation method that addresses these issues and has the following attributes: (1) Reduces the number of inefficient data structures used in the parallel program; (2) Transforms a program into a form that is more suited to identifying parallel skeletons; (3) Automatically identifies skeletons that can be efficiently executed using their parallel implementations. Our transformation method does not place restrictions on the program to be parallelised, and allows automatic verification of skeleton operator properties to allow parallel execution.
To evaluate the performance of our transformation method, we use a set of benchmark programs. The parallel version of each program produced by our method is compared with other versions of the program, including parallel versions that are derived by hand. Consequently, we have been able to evaluate the strengths and weaknesses of the proposed transformation method. The results demonstrate improvements in the efficiency of parallel programs produced in some examples, and also highlight the role of some intermediate data structures required for parallelisation in other examples
Normalisierung und partielle Auswertung von funktional-logischen Programmen
This thesis deals with the development of a normalization scheme and a partial evaluator for the functional logic programming language Curry. The functional logic programming paradigm combines the two most important fields of declarative programming, namely functional and logic programming. While functional languages provide concepts such as algebraic data types, higher-order functions or demanddriven evaluation, logic languages usually support a non-deterministic evaluation and a built-in search for results. Functional logic languages finally combine these two paradigms in an integrated way, hence providing multiple syntactic constructs and concepts to facilitate the concise notation of high-level programs. However, both the variety of syntactic constructs and the high degree of abstraction complicate the translation into efficient target programs. To reduce the syntactic complexity of functional logic languages, a typical compilation scheme incorporates a normalization phase to subsequently replace complex constructs by simpler ones until a minimal language subset is reached. While the individual transformations are usually simple, they also have to be correctly combined to make the syntactic constructs interact in the intended way. The efficiency of normalized programs can then be improved by means of different optimization techniques. A very powerful optimization technique is the partial evaluation of programs. Partial evaluation basically anticipates the execution of certain program fragments at compile time and computes a semantically equivalent program, which is usually more efficient at run time. Since partial evaluation is a fully automatic optimization technique, it can also be incorporated into the normal compilation scheme of programs. Nevertheless, this also requires termination of the optimization process, which establishes one of the main challenges for partial evaluation besides semantic equivalence. In this work we consider the language Curry as a representative of the functional logic programming paradigm. We develop a formal representation of the normalization process of Curry programs into a kernel language, while respecting the interference of different language constructs. We then define the dynamic semantics of this kernel language, before we subsequently develop a partial evaluation scheme and show its correctness and termination. Due to the previously described normalization process, this scheme is then directly applicable to arbitrary Curry programs. Furthermore, the implementation of a practical partial evaluator is sketched based on the partial evaluation scheme, and its applicability and usefulness is documented by a variety of typical partial evaluation examples
Recommended from our members
Staged generic programming
Generic programming libraries such as Scrap Your Boilerplate eliminate the need to write repetitive code, but typically introduce significant performance overheads.
This leaves programmers with the regrettable choice between writing succinct but slow programs and writing tedious but efficient programs.
Applying structured multi-stage programming techniques transforms Scrap Your Boilerplate from an inefficient library into a typed optimising code generator, bringing its performance in line with hand-written code, and so combining high-level programming with uncompromised performance.</jats:p
Programs as Diagrams: From Categorical Computability to Computable Categories
This is a draft of the textbook/monograph that presents computability theory
using string diagrams. The introductory chapters have been taught as graduate
and undergraduate courses and evolved through 8 years of lecture notes. The
later chapters contain new ideas and results about categorical computability
and some first steps into computable category theory. The underlying
categorical view of computation is based on monoidal categories with program
evaluators, called *monoidal computers*. This categorical structure can be
viewed as a single-instruction diagrammatic programming language called Run,
whose only instruction is called RUN. This version: improved text, moved the
final chapter to the next volume. (The final version will continue lots of
exercises and workouts, but already this version has severely degraded graphics
to meet the size bounds.)Comment: 150 pages, 81 figure
Finding The Lazy Programmer's Bugs
Traditionally developers and testers created huge numbers of explicit tests, enumerating interesting cases, perhaps
biased by what they believe to be the current boundary conditions of the function being tested. Or at
least, they were supposed to.
A major step forward was the development of property testing. Property testing requires the user to write a few
functional properties that are used to generate tests, and requires an external library or tool to create test data
for the tests. As such many thousands of tests can be created for a single property. For the purely functional
programming language Haskell there are several such libraries; for example QuickCheck [CH00], SmallCheck
and Lazy SmallCheck [RNL08].
Unfortunately, property testing still requires the user to write explicit tests. Fortunately, we note there are
already many implicit tests present in programs. Developers may throw assertion errors, or the compiler may
silently insert runtime exceptions for incomplete pattern matches.
We attempt to automate the testing process using these implicit tests. Our contributions are in four main
areas: (1) We have developed algorithms to automatically infer appropriate constructors and functions needed
to generate test data without requiring additional programmer work or annotations. (2) To combine the
constructors and functions into test expressions we take advantage of Haskell's lazy evaluation semantics by
applying the techniques of needed narrowing and lazy instantiation to guide generation. (3) We keep the type
of test data at its most general, in order to prevent committing too early to monomorphic types that cause
needless wasted tests. (4) We have developed novel ways of creating Haskell case expressions to inspect elements
inside returned data structures, in order to discover exceptions that may be hidden by laziness, and to make
our test data generation algorithm more expressive.
In order to validate our claims, we have implemented these techniques in Irulan, a fully automatic tool for
generating systematic black-box unit tests for Haskell library code. We have designed Irulan to generate high
coverage test suites and detect common programming errors in the process
Getting to the Point. Index Sets and Parallelism-Preserving Autodiff for Pointful Array Programming
We present a novel programming language design that attempts to combine the
clarity and safety of high-level functional languages with the efficiency and
parallelism of low-level numerical languages. We treat arrays as
eagerly-memoized functions on typed index sets, allowing abstract function
manipulations, such as currying, to work on arrays. In contrast to composing
primitive bulk-array operations, we argue for an explicit nested indexing style
that mirrors application of functions to arguments. We also introduce a
fine-grained typed effects system which affords concise and
automatically-parallelized in-place updates. Specifically, an associative
accumulation effect allows reverse-mode automatic differentiation of in-place
updates in a way that preserves parallelism. Empirically, we benchmark against
the Futhark array programming language, and demonstrate that aggressive
inlining and type-driven compilation allows array programs to be written in an
expressive, "pointful" style with little performance penalty.Comment: 31 pages with appendix, 11 figures. A conference submission is still
under revie
Cheap deforestation for non-strict functional languages
In functional languages intermediate data structures are often used as glue to
connect separate parts of a program together. Deforestation is the process
of automatically removing intermediate data structures. In this thesis we
present and analyse a new approach to deforestation. This new approach is
both practical and general.
We analyse in detail the problem of list removal rather than the more general
problem of arbitrary data structure removal. This more limited scope allows
a complete evaluation of the pragmatic aspects of using our deforestation
technology.
We have implemented our list deforestation algorithm in the Glasgow Haskell
compiler. Our implementation has allowed practical feedback. One important
conclusion is that a new analysis is required to infer function arities
and the linearity of lambda abstractions. This analysis renders the basic
deforestation algorithm far more effective.
We give a detailed assessment of our implementation of deforestation. We
measure the effectiveness of our deforestation on a suite of real application
programs. We also observe the costs of our deforestation algorithm
Knit&Frog: Pattern matching compilation for custom memory representations
Initially present only in functional languages such as OCaml and Haskell, Algebraic Data Types have now become pervasive in mainstream languages, providing nice data abstractions and an elegant way to express functions though pattern-matching. Numerous approaches have been designed to compile rich pattern matching to cleverly designed, ecient decision trees. However, these approaches are specic to a choice of internal memory representation which must accommodate garbage-collection and polymorphism. ADTs now appear in languages more liberal in their memory representation such as Rust. Notably, Rust is now introducing more and more optimizations of the memory layout of Algebraic Data Types. As memory representation and compilation are interdependent, it raises the question of pattern matching compilation in the presence of non-regular, potentially customized, memory layouts. In this report, we present Knit&Frog, a framework to compile pattern-matching for monomorphic ADTs, parametrized by an arbitrary memory representation. We propose a novel way to describe choices of memory representation along with a validity condition under which we prove the correctness of our compilation scheme. The approach is implemented in a prototype tool ribbit.Initialement présents dans les langages fonctionnels comme Ocaml et Haskell, les types algébriques sont maintenant de plus en plus présents dans les langages mainstream comme Rust. Ils permettent une abstraction commode des données et une façon élégante de décrire des fonctions via le fitrage de motifs (pattern-matching). Ce rapport de recherche présente Knit&Frog, un cadre formel pour décrire des représentations mémoires de types algébrique paramétré par la représentation mémoire. La correction de l'algorithme est prouvée sous une hypothÚse de validité de la représentation. L'algorithme est implémenté dans l'outil ribbit. Le principal avantage de l'approche est l'indépendance de l'algorithme et de sa représentation mémoire,qui permettra à terme de décrire des représentations optimisées sans perdre de l'expressivité