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