removing dead stuff
This commit is contained in:
parent
ff7fdbc378
commit
5349767531
|
@ -1,2 +0,0 @@
|
||||||
#lang info
|
|
||||||
(define scribblings '(["racket2.scrbl" (multi-page) (language)]))
|
|
|
@ -1,364 +0,0 @@
|
||||||
#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.
|
|
||||||
|
|
||||||
XXX identifier freedom with forced whitespace
|
|
||||||
|
|
||||||
@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].)
|
|
||||||
|
|
||||||
XXX algebra of interfaces (combine, extend, cut, contract, etc)
|
|
||||||
|
|
||||||
@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
|
|
||||||
|
|
||||||
XXX using struct transformers like this (and similar ones for other
|
|
||||||
types) give you access to more efficient generic operations, methods,
|
|
||||||
etc, and encourages you to write "typed" programs.
|
|
||||||
|
|
||||||
XXX seals as a more fundamental feature?
|
|
||||||
|
|
||||||
@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};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}|
|
|
||||||
|
|
||||||
XXX generics for stuff like string? via the same mechanism?
|
|
Loading…
Reference in New Issue
Block a user