A Modern Reversible Programming Language April 10, 2015
Total Page:16
File Type:pdf, Size:1020Kb
Load more
Recommended publications
-
An Array-Oriented Language with Static Rank Polymorphism
An array-oriented language with static rank polymorphism Justin Slepak, Olin Shivers, and Panagiotis Manolios Northeastern University fjrslepak,shivers,[email protected] Abstract. The array-computational model pioneered by Iverson's lan- guages APL and J offers a simple and expressive solution to the \von Neumann bottleneck." It includes a form of rank, or dimensional, poly- morphism, which renders much of a program's control structure im- plicit by lifting base operators to higher-dimensional array structures. We present the first formal semantics for this model, along with the first static type system that captures the full power of the core language. The formal dynamic semantics of our core language, Remora, illuminates several of the murkier corners of the model. This allows us to resolve some of the model's ad hoc elements in more general, regular ways. Among these, we can generalise the model from SIMD to MIMD computations, by extending the semantics to permit functions to be lifted to higher- dimensional arrays in the same way as their arguments. Our static semantics, a dependent type system of carefully restricted power, is capable of describing array computations whose dimensions cannot be determined statically. The type-checking problem is decidable and the type system is accompanied by the usual soundness theorems. Our type system's principal contribution is that it serves to extract the implicit control structure that provides so much of the language's expres- sive power, making this structure explicitly apparent at compile time. 1 The Promise of Rank Polymorphism Behind every interesting programming language is an interesting model of com- putation. -
Bringing GNU Emacs to Native Code
Bringing GNU Emacs to Native Code Andrea Corallo Luca Nassi Nicola Manca [email protected] [email protected] [email protected] CNR-SPIN Genoa, Italy ABSTRACT such a long-standing project. Although this makes it didactic, some Emacs Lisp (Elisp) is the Lisp dialect used by the Emacs text editor limitations prevent the current implementation of Emacs Lisp to family. GNU Emacs can currently execute Elisp code either inter- be appealing for broader use. In this context, performance issues preted or byte-interpreted after it has been compiled to byte-code. represent the main bottleneck, which can be broken down in three In this work we discuss the implementation of an optimizing com- main sub-problems: piler approach for Elisp targeting native code. The native compiler • lack of true multi-threading support, employs the byte-compiler’s internal representation as input and • garbage collection speed, exploits libgccjit to achieve code generation using the GNU Com- • code execution speed. piler Collection (GCC) infrastructure. Generated executables are From now on we will focus on the last of these issues, which con- stored as binary files and can be loaded and unloaded dynamically. stitutes the topic of this work. Most of the functionality of the compiler is written in Elisp itself, The current implementation traditionally approaches the prob- including several optimization passes, paired with a C back-end lem of code execution speed in two ways: to interface with the GNU Emacs core and libgccjit. Though still a work in progress, our implementation is able to bootstrap a func- • Implementing a large number of performance-sensitive prim- tional Emacs and compile all lexically scoped Elisp files, including itive functions (also known as subr) in C. -
Hop Client-Side Compilation
Chapter 1 Hop Client-Side Compilation Florian Loitsch1, Manuel Serrano1 Abstract: Hop is a new language for programming interactive Web applications. It aims to replace HTML, JavaScript, and server-side scripting languages (such as PHP, JSP) with a unique language that is used for client-side interactions and server-side computations. A Hop execution platform is made of two compilers: one that compiles the code executed by the server, and one that compiles the code executed by the client. This paper presents the latter. In order to ensure compatibility of Hop graphical user interfaces with popular plain Web browsers, the client-side Hop compiler has to generate regular HTML and JavaScript code. The generated code runs roughly at the same speed as hand- written code. Since the Hop language is built on top of the Scheme program- ming language, compiling Hop to JavaScript is nearly equivalent to compiling Scheme to JavaScript. SCM2JS, the compiler we have designed, supports the whole Scheme core language. In particular, it features proper tail recursion. How- ever complete proper tail recursion may slow down the generated code. Despite an optimization which eliminates up to 40% of instrumentation for tail call in- tensive benchmarks, worst case programs were more than two times slower. As a result Hop only uses a weaker form of tail-call optimization which simplifies recursive tail-calls to while-loops. The techniques presented in this paper can be applied to most strict functional languages such as ML and Lisp. SCM2JS can be downloaded at http://www-sop.inria.fr/mimosa/person- nel/Florian.Loitsch/scheme2js/. -
SI 413, Unit 3: Advanced Scheme
SI 413, Unit 3: Advanced Scheme Daniel S. Roche ([email protected]) Fall 2018 1 Pure Functional Programming Readings for this section: PLP, Sections 10.7 and 10.8 Remember there are two important characteristics of a “pure” functional programming language: • Referential Transparency. This fancy term just means that, for any expression in our program, the result of evaluating it will always be the same. In fact, any referentially transparent expression could be replaced with its value (that is, the result of evaluating it) without changing the program whatsoever. Notice that imperative programming is about as far away from this as possible. For example, consider the C++ for loop: for ( int i = 0; i < 10;++i) { /∗ some s t u f f ∗/ } What can we say about the “stuff” in the body of the loop? Well, it had better not be referentially transparent. If it is, then there’s no point in running over it 10 times! • Functions are First Class. Another way of saying this is that functions are data, just like any number or list. Functions are values, in fact! The specific privileges that a function earns by virtue of being first class include: 1) Functions can be given names. This is not a big deal; we can name functions in pretty much every programming language. In Scheme this just means we can do (define (f x) (∗ x 3 ) ) 2) Functions can be arguments to other functions. This is what you started to get into at the end of Lab 2. For starters, there’s the basic predicate procedure?: (procedure? +) ; #t (procedure? 10) ; #f (procedure? procedure?) ; #t 1 And then there are “higher-order functions” like map and apply: (apply max (list 5 3 10 4)) ; 10 (map sqrt (list 16 9 64)) ; '(4 3 8) What makes the functions “higher-order” is that one of their arguments is itself another function. -
Compendium of Technical White Papers
COMPENDIUM OF TECHNICAL WHITE PAPERS Compendium of Technical White Papers from Kx Technical Whitepaper Contents Machine Learning 1. Machine Learning in kdb+: kNN classification and pattern recognition with q ................................ 2 2. An Introduction to Neural Networks with kdb+ .......................................................................... 16 Development Insight 3. Compression in kdb+ ................................................................................................................. 36 4. Kdb+ and Websockets ............................................................................................................... 52 5. C API for kdb+ ............................................................................................................................ 76 6. Efficient Use of Adverbs ........................................................................................................... 112 Optimization Techniques 7. Multi-threading in kdb+: Performance Optimizations and Use Cases ......................................... 134 8. Kdb+ tick Profiling for Throughput Optimization ....................................................................... 152 9. Columnar Database and Query Optimization ............................................................................ 166 Solutions 10. Multi-Partitioned kdb+ Databases: An Equity Options Case Study ............................................. 192 11. Surveillance Technologies to Effectively Monitor Algo and High Frequency Trading .................. -
Application and Interpretation
Programming Languages: Application and Interpretation Shriram Krishnamurthi Brown University Copyright c 2003, Shriram Krishnamurthi This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 United States License. If you create a derivative work, please include the version information below in your attribution. This book is available free-of-cost from the author’s Web site. This version was generated on 2007-04-26. ii Preface The book is the textbook for the programming languages course at Brown University, which is taken pri- marily by third and fourth year undergraduates and beginning graduate (both MS and PhD) students. It seems very accessible to smart second year students too, and indeed those are some of my most successful students. The book has been used at over a dozen other universities as a primary or secondary text. The book’s material is worth one undergraduate course worth of credit. This book is the fruit of a vision for teaching programming languages by integrating the “two cultures” that have evolved in its pedagogy. One culture is based on interpreters, while the other emphasizes a survey of languages. Each approach has significant advantages but also huge drawbacks. The interpreter method writes programs to learn concepts, and has its heart the fundamental belief that by teaching the computer to execute a concept we more thoroughly learn it ourselves. While this reasoning is internally consistent, it fails to recognize that understanding definitions does not imply we understand consequences of those definitions. For instance, the difference between strict and lazy evaluation, or between static and dynamic scope, is only a few lines of interpreter code, but the consequences of these choices is enormous. -
Supporting Return-Value Optimisation in Coroutines
Document P1663R0 Reply To Lewis Baker <[email protected]> Date 2019-06-18 Audience Evolution Supporting return-value optimisation in coroutines Abstract 2 Background 3 Motivation 4 RVO for coroutines and co_await expressions 6 Return-Value Optimisation for normal functions 6 Return-Value Optimisation for co_await expressions 8 Status Quo 8 Passing a handle to the return-value slot 8 Resuming with an exception 10 Multiple Resumption Paths and Symmetric Transfer 10 Simplifying the Awaiter concept 11 Specifying the return-type of an awaitable 12 Calculating the address of the return-value 12 Benefits and Implications of RVO-style awaitables 14 Generalising set_exception() to set_error<E>() 17 Avoiding copies when returning a temporary 17 A library solution to avoiding construction of temporaries 19 Language support for avoiding construction of temporaries 21 Avoiding copies for nested calls 22 Adding support for this incrementally 23 Conclusion 24 Acknowledgements 24 Appendix - Examples 25 Abstract Note that this paper is intended to motivate the adoption of changes described in P1745R0 for C++20 to allow adding support for async RVO in a future version of C++. The changes described in this paper can be added incrementally post-C++20. The current design of the coroutines language feature defines the lowering of a co_await expression such that the result of the expression is produced by a call to the await_resume() method on the awaiter object. This design means that a producer that asynchronously produces a value needs to store the value somewhere before calling .resume() so that the await_resume() method can then return that value. -
A History of Clojure
A History of Clojure RICH HICKEY, Cognitect, Inc., USA Shepherd: Mira Mezini, Technische Universität Darmstadt, Germany Clojure was designed to be a general-purpose, practical functional language, suitable for use by professionals wherever its host language, e.g., Java, would be. Initially designed in 2005 and released in 2007, Clojure is a dialect of Lisp, but is not a direct descendant of any prior Lisp. It complements programming with pure functions of immutable data with concurrency-safe state management constructs that support writing correct multithreaded programs without the complexity of mutex locks. Clojure is intentionally hosted, in that it compiles to and runs on the runtime of another language, such as the JVM. This is more than an implementation strategy; numerous features ensure that programs written in Clojure can leverage and interoperate with the libraries of the host language directly and efficiently. In spite of combining two (at the time) rather unpopular ideas, functional programming and Lisp, Clojure has since seen adoption in industries as diverse as finance, climate science, retail, databases, analytics, publishing, healthcare, advertising and genomics, and by consultancies and startups worldwide, much to the career-altering surprise of its author. Most of the ideas in Clojure were not novel, but their combination puts Clojure in a unique spot in language design (functional, hosted, Lisp). This paper recounts the motivation behind the initial development of Clojure and the rationale for various design decisions and language constructs. It then covers its evolution subsequent to release and adoption. CCS Concepts: • Software and its engineering ! General programming languages; • Social and pro- fessional topics ! History of programming languages. -
Tail Recursion • Natural Recursion with Immutable Data Can Be Space- Inefficient Compared to Loop Iteration with Mutable Data
CS 251 SpringFall 2019 2020 Principles of of Programming Programming Languages Languages Ben Wood Topics λ Ben Wood Recursion is an elegant and natural match for many computations and data structures. Tail Recursion • Natural recursion with immutable data can be space- inefficient compared to loop iteration with mutable data. • Tail recursion eliminates the space inefficiency with a +tail.rkt simple, general pattern. • Recursion over immutable data expresses iteration more clearly than loop iteration with mutable state. • More higher-order patterns: fold https://cs.wellesley.edu/~cs251/s20/ Tail Recursion 1 Tail Recursion 2 Naturally recursive factorial CS 240-style machine model Registers Code Stack (define (fact n) Call frame (if (= n 0) 1 Call frame (* n (fact (- n 1))))) Call frame Heap arguments, variables, fixed size, general purpose general size, fixed return address per function call Space: O( ) Program How efficient is this implementation? Counter cons cells, Time: O( ) Stack data structures, … Pointer Tail Recursion 3 Tail Recursion 4 Evaluation (define (fact n) (if (= n 0) Naturally recursive factorial example 1 (* n (fact (- n 1))))) Call stacks at each step (fact 3) (fact 3): 3*_ (fact 3): 3*_ (fact 3): 3*_ (define (fact n) (fact 2) (fact 2): 2*_ (fact 2): 2*_ (if (= n 0) Compute result so far Base case returns 1 after/from recursive call. (fact 1) (fact 1): 1*_ base result. Remember: n ↦ 2; and (* n (fact (- n 1))))) “rest of function” for this call. (fact 0) Recursive case returns result so far. Compute remaining argument before/for recursive call. (fact 3): 3*_ (fact 3): 3*_ (fact 3): 3*_ (fact 3): 3*2 (fact 2): 2*_ (fact 2): 2*_ (fact 2): 2*1 Space: O( ) (fact 1): 1*_ (fact 1): 1*1 Time: O( ) (fact 0): 1 Tail Recursion 5 Tail Recursion 6 Tail recursive factorial Common patterns of work Accumulator parameter Natural recursion: Tail recursion: provides result so far. -
Interprocedural Control Flow Analysis of First-Order Programs with Tail Call Optimization 1 Introduction
Interpro cedural Control Flow Analysis of FirstOrder Programs with Tail Call Optimization Saumya K Debray and To dd A Pro ebsting Department of Computer Science The University of Arizona Tucson AZ USA Email fdebray toddgcsarizonaedu Decemb er Abstract The analysis of control ow Involves guring out where returns will go How this may b e done With items LR and Is what in this pap er we show Intro duction Most co de optimizations dep end on control ow analysis typically expressed in the form of a control ow graph Traditional algorithms construct intrapro cedural ow graphs which do not account for control ow b etween pro cedures Optimizations that dep end on this limited information cannot consider the b e havior of other pro cedures Interpro cedural versions of these optimizations must capture the ow of control across pro cedure b oundaries Determining interpro cedural control ow for rstorder programs is relatively straightforward in the absence of tail call optimization since pro cedures return control to the p oint imme diately after the call Tail call optimization complicates the analysis b ecause returns may transfer control to a pro cedure other than the active pro cedures caller The problem can b e illustrated by the following simple program that tak es a list of values and prints in their original order all the values that satisfy some prop erty eg exceed To take advantage of tailcall optimization it uses an accumulator to collect these values as it traverses the input list However this causes the order of the values in the -
Principles of Programming Languages from Recursion to Iteration Through CPS
Principles of Programming Languages From Recursion to Iteration Through CPS 1/71 The Problem We’re Solving Today We observed in a previous lecture that with our L5 interpreter because it is executed in a JavaScript interpreter which does NOT implement Tail Call Optimization, we run out of stack space even when we execute a tail-recursive function in L5. 2/71 The Problem We’re Solving Today In this section, we introduce a general method which models recursion explicitly - so that we can properly implement tail-recursion as iteration even when our meta-language does not support tail call optimization. In other words, our implementer explains how to turn tail recursion into iteration. 3/71 The Problem We’re Solving Today We first illustrate the general approach ona concrete example (a simple tail recursive function written in TypeScript, which we turn into an equivalent iterative program in JavaScript through gradual semantic transformations). 4/71 The Problem We’re Solving Today We then implement the same method on the L5 interpreter and obtain an iterative version of the interpreter. We finally demonstrate that when we execute the iterative interpreter on a tail-recursive L5 program, this yields an iterative execution process which does not consume control memory. 5/71 The Problem We’re Solving Today The end-result is an interpreter which executes tail-recursive programs as iteration even though the meta-language does not implement tail recursion optimization. 6/71 From Recursion to Tail Recursion Using the CPS Transformation Consider the following recursive function in TypeScript: const sum = (n: number): number => (n === 0) ? 0 : n + sum(n - 1); 7/71 From Recursion to Tail Recursion Using the CPS Transformation This function is recursive (because the recursive call does not appear in tail position). -
Chapter 1 Basic Principles of Programming Languages
Chapter 1 Basic Principles of Programming Languages Although there exist many programming languages, the differences among them are insignificant compared to the differences among natural languages. In this chapter, we discuss the common aspects shared among different programming languages. These aspects include: programming paradigms that define how computation is expressed; the main features of programming languages and their impact on the performance of programs written in the languages; a brief review of the history and development of programming languages; the lexical, syntactic, and semantic structures of programming languages, data and data types, program processing and preprocessing, and the life cycles of program development. At the end of the chapter, you should have learned: what programming paradigms are; an overview of different programming languages and the background knowledge of these languages; the structures of programming languages and how programming languages are defined at the syntactic level; data types, strong versus weak checking; the relationship between language features and their performances; the processing and preprocessing of programming languages, compilation versus interpretation, and different execution models of macros, procedures, and inline procedures; the steps used for program development: requirement, specification, design, implementation, testing, and the correctness proof of programs. The chapter is organized as follows. Section 1.1 introduces the programming paradigms, performance, features, and the development of programming languages. Section 1.2 outlines the structures and design issues of programming languages. Section 1.3 discusses the typing systems, including types of variables, type equivalence, type conversion, and type checking during the compilation. Section 1.4 presents the preprocessing and processing of programming languages, including macro processing, interpretation, and compilation.