Persistent lists with catenation via recursive slow-down

We describe an eficient purely functional implementation of stacks with catenation. In addition to being an intriguing problem in its own right, functional implementation of catenable stacks is the tool required to add certain sophisticated programming constructs to functional programming lan.quages. Our solution has a worst-case running time of O ( 1) for each push, pop, and catenation. The best previously known solution has an O(log* k) time bound for the kth stack operation. Our solution is not only faster but simpler, and indeed we hope it may be practical. The major new ingredient in our result is a general technique that we call recursive slowdown. Recursive slow-down is an algorithmic design principle that can give constant worst-case time bounds for operations on data structures. We expect this technique to have additional applications. Indeed, we have recently been able to extend the result described here to obtain a purely functional implementation of double-ended queues with catenation that takes constant time per operation. Permission to copy without fee all or part of this material is granted provided that the copies are not made or distributed for direct commercial advantage, the ACM copyri ht notice and the %“” title of the publication and its date appear, an notice ISgiven that copyin ISby permission of the Association of Computing Machinery. o cop othenwse, or to republish, requires T /’ a fee and/or specl ICpermission. STOC’ 95, Las Vegas, Nevada, USA oACM 0-89791 -718-9/95/0005..$3 50 *Department of Computer Science, Princeton University, Princeton, NJ 08544 USA. Research supported by the Office of Naval Research, Contract No. Nooo14-91J-1463 and a United States-Israel Educational Foundation (USIEF) Fulbright Grant. hkl@cs.princeton. edu. t Department of Computer Science, princeton University, Princeton, NJ 08544 USA and NEC Institute, Princeton, NJ. Research at Princeton University partiaJly supported by the NSF, Grant No. CCR-8920505 and the Office of Naval Research, Contract No. NOO014-91-J-1463. ret@cs. princeton.edu. Robert E. Tarj ant 1 History of the Problem A persistent data structure is one in which a change to the structure can be made without destroying the old version, so that all versions of the structure persist and can be accessed or (possibly) modified. In the functional programming literature, persistent structures are often called immutable. Purely functional programming, without side effects, has the property that every structure created is automatically persistent. Persistent data structures arise not only in functional programming but also in text, program, and file editing and maintenance; computational geometry; and other algorithmic application areas. (See [5, 8,9, 10, 11, 12, 13, 14,21,28,29,30,31,32, 33, 35].) Several papers have dealt with the problem of adding persistence to general data structures in a way that is more efficient than the obvious solution of copying the entire structure whenever a change is made. In particular, Driscoll, Sarnak, Sleator, and Tarjan [11] described how to make pointer-based structures persistent using a technique called node-splitting, which is related to fractional cascading [6] in a way that is not yet fully understood. Dietz [10] described a method for making array-based structures persistent. Additional references on persistence can be found in those papers. The general techniques in [10] and [11] fail to work on data structures that can be combined with each other rather than just be changed locally. Perhaps the simplest and probably the 1For the purposes of this paper, a “purely functional” data structure is one built using only the LISP functions car, cons, cdr. Though we do not state our constructions explicitly in terms of these functions, it is routine to verify that our structures are purely functional.

[1]  Chris Okasaki,et al.  Simple and efficient purely functional queues and deques , 1995, Journal of Functional Programming.

[2]  Donald E. Knuth,et al.  The art of computer programming: V.1.: Fundamental algorithms , 1997 .

[3]  Robert HOOD,et al.  Real-Time Queue Operation in Pure LISP , 1980, Inf. Process. Lett..

[4]  Thomas W. Reps,et al.  Incremental Context-Dependent Analysis for Language-Based Editors , 1983, TOPL.

[5]  Robert E. Tarjan,et al.  Data structural bootstrapping, linear path compression, and catenable heap ordered double ended queues , 1992, Proceedings., 33rd Annual Symposium on Foundations of Computer Science.

[6]  Robert E. Tarjan,et al.  Confluently persistent deques via data structuaral bootstrapping , 1993, SODA '93.

[7]  Matthias Felleisen,et al.  Abstract continuations: a mathematical semantics for handling full jumps , 1988, LISP and Functional Programming.

[8]  Robert E. Tarjan,et al.  Fully persistent lists with catenation , 1991, SODA '91.

[9]  Matthias Felleisen,et al.  The theory and practice of first-class prompts , 1988, POPL '88.

[10]  M. H. Overmars,et al.  Searching in the past I , 1981 .

[11]  Donald Ervin Knuth,et al.  The Art of Computer Programming , 1968 .

[12]  Garret Frederick Swart,et al.  Efficient algorithms for computing geometric intersections (decision tree, hidden line removal, graphics, complexity) , 1985 .

[13]  Matthias Felleisen,et al.  A calculus for assignments in higher-order languages , 1987, POPL '87.

[14]  Benjamin Goldberg,et al.  Real-time deques, multihead Turing machines, and purely functional programming , 1993, FPCA '93.

[15]  Robert Todd Hood,et al.  The Efficient Implementation of Very-high-level Programming Language Constructs , 1982 .

[16]  Arnold L. Rosenberg,et al.  Real-Time Simulation of Multihead Tape Units , 1972, JACM.

[17]  David P. Dobkin,et al.  Efficient uses of the past , 1980, 21st Annual Symposium on Foundations of Computer Science (sfcs 1980).

[18]  Lawrence Robinson,et al.  An example of hierarchical design and proof , 1978, CACM.

[19]  Gregory F. Johnson,et al.  Stores and partial continuations as first-class objects in a language and its environment , 1988, POPL '88.

[20]  F. Warren Burton,et al.  An Efficient Functional Implementation of FIFO Queues , 1982, Information Processing Letters.

[21]  Bernard Chazelle,et al.  How to Search in History , 1983, Inf. Control..

[22]  Joel I. Seiferas,et al.  New Real-Time Simulations of Multihead Tape Units , 1977, JACM.

[23]  Donald E. Knuth,et al.  The Art of Computer Programming, Volume I: Fundamental Algorithms, 2nd Edition , 1997 .

[24]  Joel I. Seiferas,et al.  New Real-Time Simulations of Multihead Tape Units , 1981, J. ACM.

[25]  Robert E. Tarjan,et al.  Planar point location using persistent search trees , 1986, CACM.

[26]  David Gries,et al.  The Science of Programming , 1981, Text and Monographs in Computer Science.

[27]  Paul F. Dietz Fully Persistent Arrays (Extended Array) , 1989, WADS.

[28]  Rob R. Hoogerwoord,et al.  Functional Pearls A symmetric set of efficient list operations , 1992, Journal of Functional Programming.

[29]  Richard Cole,et al.  Searching and Storing Similar Lists , 2018, J. Algorithms.

[30]  John A. Allen,et al.  The anatomy of lisp , 1980 .

[31]  Robert E. Tarjan,et al.  Making data structures persistent , 1986, STOC '86.

[32]  Matthias Felleisen,et al.  Control delimiters and their hierarchies , 1990, LISP Symb. Comput..

[33]  S. Rao Kosaraju,et al.  Real-time simulation of concatenable double-ended queues by double-ended queues (Preliminary Version) , 1979, STOC.

[34]  Robert E. Tarjan,et al.  Deques with Heap Order , 1986, Inf. Process. Lett..

[35]  S. Rao Kosaraju,et al.  An optimal RAM implementation of catenable min double-ended queues , 1994, SODA '94.