[plt-dev] some Racket proposals & implementation
I just thought the auto-v change would be easier and would also make it
available to alternative structure definition macros. But, with just the
constructor naming it will be cleaner to override the default make- (or
whatever you want to call it) and roll your own.
On Fri, Apr 2, 2010 at 5:35 PM, Matthew Flatt <mflatt at cs.utah.edu> wrote:
> Support for keyword and optional arguments would be good. I don't think
> I'd extend the auto-field description, but instead have something like
>
> (define-struct a (w [x (add1 w)] #:y y #:z [z (add1 y)]))
>
> be analogous to defining the constructor as a function
>
> (lambda (w [x (add1 w)] #:y y #:z [z (add1 y)]) ...)
>
> but with the same selector functions as
>
> (define-struct a (w x y z))
>
> As another example,
>
> (define-struct a (w
> [x (add1 w)]
> #:y [y #:mutable]
> #:z [z (add1 y) #:mutable]))
>
> would have a constructor with the same signature as above, but with
> mutable `y' and `z' fields.
>
> Some challenges I see:
>
> * reporting enough static information for `match' to support the right
> syntax for patterns with `a';
>
> * subtyping of a type whose constructor uses keyword arguments;
>
> * reflective access to constructors (via `struct-type-make-constructor',
> for example); and
>
> * printing values when the constructor has keyword arguments.
>
> I think all of these can be addressed, but it's a lot of work (so if
> it depends on me, I'm inclined to put it off a while longer).
>
> At Fri, 2 Apr 2010 16:11:10 -0600, Doug Williams wrote:
> > Would it be possible to combine the structure constructor name with a
> means
> > of providing default structure values on a per slot basis? I had always
> > thought it would be nice if the auto-v argument to make-struct-type took
> an
> > old-style lambda list (i.e., an improper list or, in the degenerate case,
> an
> > atom) to allow specification of slot-specific automatic (default) values
> -
> > with the cdr of an improper list (or the atom in the degenerate case)
> being
> > used for the remaining elements. Then, define-struct could support a
> > #:default field option for each slot. Just a thought.
> >
> > On Fri, Apr 2, 2010 at 3:30 PM, Matthew Flatt <mflatt at cs.utah.edu>
> wrote:
> >
> > > Version 4.2.5.5 in the SVN trunk includes experimental features to
> > > support the following proposed Racket features. You can try the
> > > proposals with `#lang racket' in MzScheme.
> > >
> > > Structure Constructor Names
> > > ---------------------------
> > >
> > > Proposal: The default constructor name bound by `define-struct' in
> > > Racket should be the same as the type name, instead of having a `make-'
> > > prefix.
> > >
> > > Example:
> > >
> > > > (define-struct a (x y))
> > > > a
> > > #<procedure:a>
> > > > (a 1 2)
> > > #<a>
> > >
> > > To help support this potential feature, the `define-struct' form of
> > > `scheme/base' now accepts a `#:constructor-name' argument to give the
> > > constructor a name other than the one prefixed with `make-'. In
> > > particular, the constructor name can be the same as the type name:
> > >
> > > > (define-struct a (x y))
> > > > make-a
> > > #<procedure:make-a>
> > > > (define-struct a (x y) #:constructor-name a)
> > > > a
> > > #<procedure:a>
> > > > (a 1 2)
> > > #<a>
> > >
> > > A natural (and generally backward-compatible) to change to `match'
> > > would be to treat structure-type names as pattern constructors, so that
> > >
> > > (match (a 1 2)
> > > [(a x y) x])
> > >
> > > would produce 1.
> > >
> > >
> > > Semi-quasiquote Printing
> > > ------------------------
> > >
> > > Proposal: Use quasiquote printing as Racket's default printing mode,
> > > but only for transparent values.
> > >
> > > Functional programmers long ago figured out that it's better to print a
> > > value in the same way as an expression that produces the value.
> > > Printing with `quasiquote', meanwhile, mostly preserves the Lisp
> > > tradition of printing values that represent expressions as the
> > > expressions that they represent.
> > >
> > > Some values, however, cannot be printed easily as expressions that
> > > produce the same value. For example, In DrScheme with quasiquote
> > > printing,
> > >
> > > (list 1 (let ([f (lambda (x) x)]) f))
> > >
> > > prints as
> > >
> > > `(1 ,(lambda (a1) ...))
> > >
> > > The printer cannot actually print a function, so it has to invent a
> > > `lambda' expression that approximates the value. The problem is worse
> > > with objects, classes, and other opaque types. Expressions with graphs
> > > print as a `shared' expression.
> > >
> > > Other implementations of functional languages punt on opaque values.
> > > Here's an example in OCaml, which prints functions as just `<fun>':
> > >
> > > # Some 10;;
> > > - : int option = Some 10
> > > # sqrt;;
> > > - : float -> float = <fun>
> > > # [sqrt;sqrt];;
> > > - : (float -> float) list = [<fun>; <fun>]
> > >
> > > This seems like the right compromise for Racket. For example,
> > >
> > > (list 1 (let ([f (lambda (x) x)]) f))
> > >
> > > could print as
> > >
> > > `(1 #<procedure:f>)
> > >
> > > (Note that there's no need for an unquote when printing a value as a
> > > non-expression. Non-S-expression forms are "self-unquoting".)
> > >
> > > Transparent (or prtially transparent) structures can print with
> > > constructors, while opaque structures can print as non-S-expressions:
> > >
> > > > (define-struct a (x y))
> > > > (list 1 (a 2 3))
> > > `(1 #<a>)
> > > > (define-struct a (x y) #:transparent)
> > > > (list 1 (a 2 3))
> > > `(1 ,(a 2 3))
> > >
> > > Instances of prefab structure types, meanwhile, should stick to
> > > quasiquoting:
> > >
> > > > (define-struct b (x y) #:prefab)
> > > > (list 1 (b (a 2 3) 'x))
> > > `(1 #s(b ,(a 2 3) x))
> > >
> > > Graphs can still use the compact #n= notation:
> > >
> > > > (read (open-input-string "#0=(1 . #0#)"))
> > > `#0=(1 . #0#)
> > >
> > > Unlike DrScheme's quasiquote printing, semi-quasiquote printing is
> > > easily implemented by parameterizing our existing printer(s).
> > >
> > > A new `print-as-quasiquote' parameter directs `print' and
> > > `pretty-print' to use semi-quasiquote style. (The parameter does not
> > > affect `write'.)
> > >
> > > Welcome to MzScheme v4.2.5.5 [3m], Copyright (c) 2004-2010 PLT Scheme
> Inc.
> > > > 'x
> > > x
> > > > (print-as-quasiquote #t)
> > > > 'x
> > > 'x
> > > > (list 1 2 3)
> > > `(1 2 3)
> > > > sqrt
> > > #<procedure:sqrt>
> > > > (list 1 sqrt)
> > > `(1 #<procedure:sqrt>)
> > >
> > > The `port-print-handler' and `prop:write' protocols have been changed
> > > (in a mostly backward-compatible way) to make semi-quasiquote printing
> > > extensible.
> > >
> > >
> > > Language-Specific Run-Time Configuration
> > > ----------------------------------------
> > >
> > > Proposal: The main language of a program should determine a run-time
> > > configuration, including the style for printing values.
> > >
> > > Assuming the changes above, we'd want
> > >
> > > #lang scheme
> > > (define-struct a (x y) #:transparent)
> > > (list (make-a 1 2))
> > >
> > > to produce
> > >
> > > (#(struct:a 1 2))
> > >
> > > while
> > >
> > > #lang racket
> > > (define-struct a (x y) #:transparent)
> > > (list (a 1 2))
> > >
> > > should produce
> > >
> > > `(,(a 1 2))
> > >
> > > Along the same lines, we'd want
> > >
> > > #lang scheme
> > > (define-struct a (x y) #:transparent)
> > > (+ 'x (list (make-a 1 2)))
> > >
> > > to produce the error message
> > >
> > > +: expects type <number> as 1st argument, given: x; other arguments
> > > were: (#(struct:a 1 2))
> > >
> > > while
> > >
> > > #lang racket
> > > (define-struct a (x y) #:transparent)
> > > (+ 'x (list (a 1 2)))
> > >
> > > should produce the error message
> > >
> > > +: expects type <number> as 1st argument, given: 'x; other arguments
> > > were: `(,(a 1 2))
> > >
> > > The different `define-struct's are easily support through different
> > > bindings imported by `scheme' and `racket'. Similarly, for printing
> > > top-level results in a module, you might imagine that `scheme' and
> > > `racket' use different printing functions. The different error formats,
> > > however, are not so easily controlled through bindings.
> > >
> > > Setting `print-as-quasiquote' to #t is enough to get the Racket-style
> > > error format, but having `#lang racket' inject `(print-as-quasiquote
> > > #t)' in the module top-level would not work well when modules from
> > > different languages are mixed together. For example, if a program
> > > imports both
> > >
> > > ;; s.ss:
> > > #lang scheme
> > > (define (s-bad v) (error 's-bad "~e" v))
> > > (provide s-bad)
> > >
> > > and
> > >
> > > ;; r.rkt
> > > #lang racket
> > > (define (r-bad v) (error 'r-bad "~e" v))
> > > (provide r-bad)
> > >
> > > the way an error message is printed by `s-bad' and `r-bad' shouldn't
> > > depend on the order that the modules are instantiated.
> > >
> > > To accommodate run-time configuration of the environment, such as
> > > setting the way that values are printed, `mzscheme' now treats the main
> > > module of a program specially. It extracts information about the
> > > module's language --- specifically, whether the language declares a
> > > run-time configuration action. If so, `mzscheme' runs the
> > > language-configuration action before it instantiates the module.
> > >
> > > As a result, when you put either version of the code above in "ex.ss",
> > > then `mzscheme ex.ss' produces the right error message.
> > >
> > > Here's how it works in more detail for the case of `#lang racket':
> > >
> > > * The `racket' module reader has implemented in `racket/lang/reader'
> > > associates a 'module-language property with `module' form that it
> > > produces from "ex.ss". The 'module-language property essentially
> > > points back to `racket/lang/reader'.
> > >
> > > * The macro expander and bytecode compiler preserves the
> > > 'module-language information so that it's available through
> > > `module-compiled-language-info' (from the unevaluated bytecode)
> > > and/or `module->language-info' (from the evaluated module
> > > declaration).
> > >
> > > * When the `mzscheme' executable is given a module to run, it uses
> > > `module->language-info' to get the module's language information
> > > before `require'ing the module. The `module->language-info' loads
> > > "ex.ss" (from source or bytecode) and extracts language info from
> > > the declared module.
> > >
> > > The language info on the declaration of the module from "ex.ss"
> > > points back to the `get-info' export of `racket/lang/reader'. The
> > > `mzscheme' executable calls that function with the
> > > 'configure-runtime key.
> > >
> > > * The `get-info' function of `racket/lang/reader' recognizes the
> > > 'configure-runtime key and reports back the `configure' function
> > > provided by `racket/private/runtime'.
> > >
> > > [Why doesn't `get-info' just call `configure' directly? See below
> > > on creating executables.]
> > >
> > > * The `mzscheme' executable calls the `configure' function of
> > > `racket/private/runtime' calls it. The `configure' function simply
> > > sets the `print-as-quasiquote' parameter to #t.
> > >
> > > * Having finished running the language's configuration action, the
> > > `mzscheme' executable `require's the "ex.ss" module to instantiate
> > > it. (Although `module->language-info' has already loaded the module,
> > > `module->language-info' doesn't instantiate the module.)
> > >
> > > Instantiating the module runs the expressions in its body,
> > > triggering the `+' error. The error message uses the right style for
> > > printing values because the `print-as-quasiquote' parameter was set
> > > to #t by `configure'.
> > >
> > > If you run `mzc --exe ex ex.ss', the generated executable prints the
> > > right error message, too. That's because `mzc' extracts the main
> > > module's language information in the same way as `mzscheme'. Based on
> > > the result for 'confgure-runtime for the module's language, `mzc'
> > > embeds the `racket/private/runtime' module in the generated executable
> > > (and that's why `get-info' doesn't call `configure' itself). The
> > > generated executable includes a start-up action that calls `configure'
> > > before running the main module.
> > >
> > >
> > > DrScheme should similarly extract language information and call
> > > `configure' before running the module. It may be that a single
> > > side-affecting `configure' function isn't the right interface for
> > > DrScheme, and so experiments with DrScheme may lead to a different
> > > protocol for `mzscheme' and `mzc'.
> > >
> > >
> > > When `mzscheme' is run in interactive module, the initialization
> > > module's language is used to initialize the run-time configuration. The
> > > `racket', `racket/base' and `racket/init' modules are implemented in
> > > Racket, so
> > >
> > > mzscheme -I racket/init
> > >
> > > gives you a REPL like `racket' could give you (when it exists).
> > >
> > > _________________________________________________
> > > For list-related administrative tasks:
> > > http://list.cs.brown.edu/mailman/listinfo/plt-dev
> > >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/dev/archive/attachments/20100402/1a684700/attachment.html>