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