From be30e8556e30d64fb56decb98876ae72d76a732b Mon Sep 17 00:00:00 2001 From: Jay McCarthy Date: Mon, 7 Oct 2013 20:48:50 -0600 Subject: [PATCH] First draft --- info.rkt | 3 + scribblings/racket2/info.rkt | 2 + scribblings/racket2/racket2.scrbl | 352 ++++++++++++++++++++++++++++++ 3 files changed, 357 insertions(+) create mode 100644 info.rkt create mode 100644 scribblings/racket2/info.rkt create mode 100644 scribblings/racket2/racket2.scrbl diff --git a/info.rkt b/info.rkt new file mode 100644 index 0000000..e059f0c --- /dev/null +++ b/info.rkt @@ -0,0 +1,3 @@ +#lang info +(define version "0.0") +(define collection 'multi) diff --git a/scribblings/racket2/info.rkt b/scribblings/racket2/info.rkt new file mode 100644 index 0000000..969a8cc --- /dev/null +++ b/scribblings/racket2/info.rkt @@ -0,0 +1,2 @@ +#lang info +(define scribblings '(["racket2.scrbl" (multi-page) (language)])) diff --git a/scribblings/racket2/racket2.scrbl b/scribblings/racket2/racket2.scrbl new file mode 100644 index 0000000..4e993a2 --- /dev/null +++ b/scribblings/racket2/racket2.scrbl @@ -0,0 +1,352 @@ +#lang scribble/manual + +@title{Racket 2} +@author{Jay McCarthy} + +This document attempts to describe Racket 2. + +@table-of-contents[] + +@section{Introduction} + +My dream for Racket is based on two things: + +@itemlist[ + +@item{Racket will be a full spectrum programming language, meaning +that it supports programming at all levels. We traditionally +understand this under the rubric of "from scripts to programs" that +inspired Typed Racket, but we could go much further in our ability to +verify programs, such as by producing Pure Racket, Total Racket, and +VeriRacket. Along another dimension of the spectrum, we could offer +more and more control of the low-level details of programming, such as +with safe manual memory management and data representation control.} + +@item{Racket will be a language with an extensible compiler.} + +] + +I believe that the first goal is a philosophical goal while the second +is a technical goal. I think the two goals work together because we +believe that the extensible compiler is the tool with which we will +spread across the full spectrum. + +I do not believe we can achive these goals if we are not flexible in +our understanding of what is Racket and what isn't, nor if we are so +attached to historical coincidence that we cannot accept changes. + +Nevertheless, Racket is more than just an academic pursuit of +perfection, but we desire it to be usable for practical programming +today and each day along the way. We often understand this constraint +as our commitment to backwards compatibility. + +We are at a moment in Racket's history where many of us feel a desire +for a major break in compatibility to increase our flexibility in the +future. This document attempts to structure this moment so we can make +the most of it. + +@subsection{Structure} + +I believe that for the process of creating Racket 2 to be productive, +we need to decide when we will stop changing it and settle in to +a "new normal". Similarly, it would be desirable to have a criteria to +decide whether feature X or Y is more in line with the vision of +Racket 2. + +At this moment, I do not have an idea of the principle that will guide +Racket 2. I hope as I write this document, I will discover it. But +lacking a certain principle, I propose that we allocate ourselves a +fixed amount of changes to the Racket 2 design document. For instance, +we could say that we will revise the design six times, meaning that +there will be six "beta" releases of Racket 2 before we solidify it +and live with it for a while. I don't think it matters so much how +many we give ourselves or what constitutes a release, but I think a +process like this could work well. + +One principle may be, "Make it easy to do the right thing." Another +is "Transformers everywhere." + +@subsection{The Scope of Racket 2} + +I think a useful way to think about the scope of Racket 2 is to +imagine that we are writing a new Reference manual. We must decide +what things are described by the Reference (i.e. which things are +core) and how they are described. This includes the syntactic forms, +core data-structures, modularity mechanisms, etc. It leaves out the +way Racket 2 influences outside libraries, etc. + +In particular, I think that the Reference is not an appropriate place +to write about implementation details and how the virtual machine +works. In other words, in our discussion of Racket 2, I hope that we +can focus on the end-programmer experience and assume that the virtual +machine is what it is. + +Based on this scope, the rest of this document is written as if it is +the new Reference, although with only the changed and interesting +parts left in. + +@section{Language Model} +@subsection{The Reader} + +R2's syntax is a combination of Honu and the @"@"-reader. + +@emph{Why Honu?} Racket is defined as having an extensible +compiler. In R1, this was only possible by using S-expressions to +build on existing macro technology. Now that we have discovered Honu, +we must push it to develop a new kind of extensible compiler +front-end. + +@emph{Why @"@"?} R1 has taught us the importance of embedding prose in +programs. By including the @"@"-reader at all times, we make it easier +to embed prose. + +@section{Syntactic Forms} +@subsection{Modules} + +@verbatim|{ +#lang r2 + +module duck : racket/base { } + +module* duck { } // language implicitly #f if left out + +module+ duck { } +}| + +Build-in convenient macros for defining test and main sub-modules. + +@verbatim|{ +#lang r2 + +test { } +main { } + +}| + +XXX labeled effects + +@subsection{Importing and Exporting} + +R2's importing and exporting will decrease the "nominalness" of Racket +modules by requiring interfaces to be imported and exported rather +than names alone. The existing set of @racket[require] forms will +become interface transformers and combinators to change the interface +before using it. + +@verbatim|{ +#lang r2/base +open racket/list, racket/dict; // Open gets the interfaces, but not + // the values or macros, thus it is like + // the current require +require list1^ from racket/list, // Require actually gets the bindings + dict1^ from racket/dict, + contract1^ from racket/contract; // Perhaps we implicitly open + // any module on the RHS of from + // and just use open for 'strange' + // interface sources + +interface database1^ { + db : any -> boolean?, // : is an interface transformer like contract-out + open : list? -> db? +}; + +provide database1^ +}| + +In the same way that today the @racketmodname[racket/base] language +is "more strict" (because it requires you to name all normal imports), +@racketmodname[r2/base] will be "more strict" as well. In particular +however, @racketmodname[r2] will allow you to use the @racket[*] +interface which is otherwise disallowed. + +@verbatim|{ +#lang r2 +require * from racket/list, + * from racket/dict; + +}| + +@emph{Why?} This serves two purposes. First, it builds a package-like +notion of versioning into every library, because you can extend the +module but not add the new features to every old interface. A single +module like @racketmodname[racket/list] could provide interfaces +@racket[list1^] and @racket[list2^]. Second, it provides more +information about what a module needs from its requires so that +modules are more analyzable. In particular, I hope that we can use +this information to make a "module consuming meta-language" to go with +our current "module producing meta-language" that will override the +sources of interfaces with different choices (i.e. a program needs +@racket[list1^] and specifies the normal list functions as the +default, but the context of the application changes it to be provided +by a version of the list modules that optimizes @racket[snoc] and +@racket[append].) + +@subsection{Procedure Expressions, Local Binding, Local Definition, Definitions, and Assignments} + +One of the earliest wishes for R2 has been "match everywhere". I think +this is a noble goal, but a more noble goal in my mind +is "transformers everywhere". In particular, transformers, like match +expanders, in binding positions. For instance, if in R1 the formals +part of a @racket[λ] had expanders, then @racket[(λ (cons x y) y)] +would be valid not because we have "match everywhere", but because +@racket[cons] would be a "binding expander" in addition to a function. + +@verbatim|{ +#lang r2 + +x = 5; // = is define + +var y = 5; // var is a binding transformer that boxes the RHS and allows mutation +y := 6; // the var binding transformer on y set up y as a := transformer to allow this to be set-box! +z = y + 4; // this is not an error because the var transformer made y the same as (unbox y) +yb = &y; // the var binding transformer on y set up y as a & transformer to allow this to get the box itself + +// This means that R2 is more like ML in that only explicitly labeled +// references are mutable and nothing else is. + +a , b = 10 `quo/rem` 3; // , is a binding transformer for values +c , d = a + 4, b - 3; // but also a normal macro for returning values + +best :: rest = range(1,10) // :: is a binding transformer for cons + +a = 5; +a = 4; // since = is define, this is an error + +a = 10; +a *= a + 1; // *= is like define* from racket/package so a is 11 from this point on + +a = { b = 4; b + 5; } // {} sets up a new scope so it is easy to have "internal definition everywhere" + +// All these transformers could be nested + +var x, y::z = 1, [3 4 5]; // x = box 1, y = 3, z = [4 5] + +// All these transformers make sense inside of function formals too + +fun f ( a::[b], var c ) { a + b } +f = λ ( a::[b], var c ) { a * c + b } +f( [ 1 2 ], 3 ) + +// But some transformers only make sense inside of function formals + +fun f ( a, [b = 60]) { a + b } // %brackets is a function binding transformer for optional arguments + +f(1) should be 61 +f(1,2) should be 3 + +fun f ( a , b = b ) { a + b } // keywords forms [left of = is the kw] +f(1, b = 3) +f(b = 3, 1) + +}| + +We drop @racket[case-lambda]. + +@subsection{Conditionals, Dispatch, Guarded Evaluation} + +@verbatim|{ +#lang r2 + +if ( true ) { .... } else { .... } +when ( true ) { .... } +unless ( false ) { .... } +cond { question: expr; question: {expr; expr}; else: expr } +switch expr { pat: expr; pat: {expr; expr}; else: expr } + +}| + +@racket[else] is a binding. If you don't have it, the default behavior +is an error message with source location information. + +@subsection{Iteration and Comprehensions} + +XXX This is a good place to do new things. + +@section{Datatypes} + +A key principle for R2's data structures is that we define common +interfaces and generic operations rather than many operations for each +kind of structures. The structures would be at least Sequences, Maps, +Sets. We prefer immutable versions of everything with the mutable +operations cordonned into a different interface. + +XXX More discussion needed here + +@section{Structures} + +We extend the idea of transformers everywhere to be inside of +structure definitions and has something that are produced by structure +definitions. + +@verbatim|{ +#lang r2 + +struct posn { + x; + y; +}; + +fun f ( posn p ) { return p.x + p.y; } +// This works because 'posn' is a binding transformer that defines p.x and p.y + +struct bullet { + posn src; + posn dest; +}; +fun f ( bullet b ) { return b.src.x; } +// This works because 'posn' is a struct field transformer that works +// with the binding transfomer. + +fun f ( x ) { return posn( x = x, y = 7 ); } +// Constructors are always by kw + +posn f ( x ) { return posn( x = x, y = 7 ); } +f(5).x;; +// This works because 'posn' is a function definition transformer that +// works with applications to communicate to . that .x is in the result +// of f() + +struct locator extends posn { + z; +}; +// Because constructors are always by kw, the parents and child +// structs cannot conflict. + +}| + +XXX use var for a field is mutable, otherwise immutable +XXX mutable fields define := transformers +XXX every struct has built-in updater that preserves sub-struct-ness +XXX structs define a single binding +XXX optional fields +XXX struct in interface is used for restricting access to pieces of structures + +@section{Classes and Objects} + +I'm tempted to say that Generics in R1 is a failure of the class +system to provide what we want. If this is the case, then I think a +simplified class system that builds on top of structures is the right +thing to do in R2. I think Go actually does something sensible here. + +@verbatim|{ +#lang r2 + +struct posn { + x; + y; +}; + +// XXX Do we mandate interfaces? Are they the same kind of interfaces +// as for modules? +posn implements { + public: + meth distanceTo ( x ) { + return this.x - x; + } + + meth updateX ( x ) { + return this.{x = x}; + } +} + +}|