Re: Introspection
Marc Nieper-Wißkirchen
(11 May 2020 07:11 UTC)
|
Multiple-values SRFI Lassi Kortela (11 May 2020 09:09 UTC)
|
Re: Multiple-values SRFI
Marc Nieper-Wißkirchen
(11 May 2020 09:41 UTC)
|
Re: Multiple-values SRFI
Lassi Kortela
(11 May 2020 10:52 UTC)
|
Re: Multiple-values SRFI
Lassi Kortela
(11 May 2020 11:04 UTC)
|
Re: Introspection
John Cowan
(11 May 2020 18:02 UTC)
|
Re: Introspection
Marc Nieper-Wißkirchen
(11 May 2020 18:26 UTC)
|
Re: Introspection
Marc Feeley
(11 May 2020 18:34 UTC)
|
Re: Introspection
Marc Nieper-Wißkirchen
(11 May 2020 19:29 UTC)
|
Re: Introspection
Marc Feeley
(12 May 2020 04:15 UTC)
|
Re: Introspection
John Cowan
(12 May 2020 15:36 UTC)
|
Re: Introspection
Lassi Kortela
(12 May 2020 16:07 UTC)
|
Re: Introspection
John Cowan
(12 May 2020 18:19 UTC)
|
Re: Introspection
Lassi Kortela
(12 May 2020 18:46 UTC)
|
Re: Introspection
Marc Nieper-Wißkirchen
(04 Jun 2020 16:39 UTC)
|
Re: Introspection
Marc Nieper-Wißkirchen
(09 Jun 2020 08:38 UTC)
|
Re: Introspection
John Cowan
(09 Jun 2020 17:53 UTC)
|
Re: Introspection
Marc Nieper-Wißkirchen
(09 Jun 2020 19:39 UTC)
|
Re: Introspection
John Cowan
(10 Jun 2020 21:46 UTC)
|
Re: Introspection
Marc Nieper-Wißkirchen
(11 Jun 2020 11:55 UTC)
|
Re: Introspection
Marc Nieper-Wißkirchen
(04 Jun 2020 16:36 UTC)
|
> I will then submit a general multiple values SRFI before SRFI 195 is > finalized (and maybe also before SRFI 189 is). This SRFI will include > syntax like > > [...] > >>> (values->vector <expr>) >>> (values-length <expr>) >>> (values->list <expr>) >>> (values-ref <expr> <index>) +1. Very nice API. I've wished for something like this. FWIW, the Common Lisp multiple values API is basically everything on the page <http://www.lispworks.com/documentation/HyperSpec/Body/c_data_a.htm> with "value" in its name: Macro MULTIPLE-VALUE-BIND Special Operator MULTIPLE-VALUE-CALL Macro MULTIPLE-VALUE-LIST Special Operator MULTIPLE-VALUE-PROG1 Macro MULTIPLE-VALUE-SETQ Accessor VALUES Function VALUES-LIST Constant Variable MULTIPLE-VALUES-LIMIT Macro NTH-VALUE NOTE: In CL, values-list means list->values, not values->list. > I am not so sure about the naming; in view of SRFI 8, it could make > sense to use names like `receive-list`, `receive-vector`. I am open to > suggestions! To me, the word "receive" connotes that it's a macro (a very nice macro, to be sure); not sure how common this association is. "Values" is a simpler, shorter word and since the term for the concept is "multiple values", it's probably more obvious if the operator names talk about "values" as well. In Common Lisp I always regretted the excessively long operator names. "multiple-value-bind" is the simplest and most common operation; as a newbie it was difficult to find. Scheme's "receive" and "let-values" are a big improvement in that sense. > Such a SRFI will also include procedures that go the other way, like > > (list->values <list>) > > which is equivalent to (apply values <list>), an often-used idiom, but > may be implemented more efficiently. +1, very useful! > Again, there may be better names, like `unpack-list` or `explode-vector`. I really like the names you chose. They are symmetrical among themselves and with the rest of Scheme, and use common words that are familiar to every Schemer. > Racket has `set!-values` > (https://docs.racket-lang.org/reference/set_.html#%28form._%28%28lib._racket%2Fprivate%2Fmore-scheme..rkt%29._set%21-values%29%29), Nice. `define-values` is already in the standard so `set!-values` is a natural complement. In Common Lisp, MULTIPLE-VALUE-SETQ. > which can slightly be generalized to also take formals with a rest > argument, and which also should go into such a multiple-values SRFI. Even nicer. Would this be best done using the consing dot? > Moreover, we have case-lambda that dispatches on the number of > arguments an ordinary procedure receives; we don't have a similar > construct for the number a continuation receives (and which could be > useful to implement some of SRFI 189's conversion procedures whose > protocol depends on the number of values). Therefore, I would also > propose > > (case-receive <expr> > (<formals> <body>) ...) > > which can be rewritten into > > (with-values <expr> > (case-lambda > ((<formals> <body>) ...) > > Here, `with-values` is of course > > (define-syntax with-values > (syntax-rules () > ((with-values expr receiver) (call-with-values (lambda () expr) receiver)))) > > (If I remember correctly, Kent Dybvig once made a point that > `with-values` should have been standardized, not `call-with-values` > because both are equivalent in expressiveness but it easier to work > with an optimize `with-values`.) LGTM. > Another part of the language, where everyone could benefit from a > better support of multiple values, are various higher-order > procedures. For example, SRFI 1 defines `fold` and `fold-right`. > `fold` is the fundamental list iteration operator and `fold-right` is > the fundamental list recursion operator. Code that uses them is > conceptionally clearer than code using hand-written loops with > named-let. The problem is, however, when more than one value has to be > threaded through the iteration or recursion. > > Most of the time, the user will have to go back to hand-written loops > but will then have to deal with `values` and `let-values` explicitly. Definitely. > However, there is no obvious generalization of `fold` and friends to > multiple values (which implies multiple seeds). The problem is the > calling convention of the procedure that is being called in each step. > Currently, it takes the accumulator and an arbitrary number of values > corresponding to the number of lists (vectors, generators, gadgets, > ...) being iterated or recursed over. A multiple-value version `fold*` > would have to apply an arbitrary number of accumulator values and an > arbitrary number of values corresponding to the number of lists > present but there is only one rest argument. IMHO the most obviously useful is (fold* step list init...) where N init values mean `step` takes N accumulators and returns N values to use as the next accumulators. At the end, `fold*` returns N values. Using multiple-value boxes, we could also do (fold* step init list...) where `init` is a box. `step` would then be called with M lists and N accumulators (in either order) and return N accumulators as values. Multiple-value boxes would work for an even more general fold* if we pass the accumulators to `step` as boxes. This may actually be less crazy than it sounds :) Perhaps instead of the most generic values-fold there should be a box-fold. In Scheme implementations with multiple-value boxes, box-fold could take advantage of them. M-v boxes a nice generalization that doesn't make the existing single-value boxes any more difficult for users. If they are easy to implement efficiently, they will hopefully be widely adopted. > One solution would be to make `fold*` into syntax, say: > > (fold* (<list-formals> <seed-formals> <body>) (<seed> ...) (<list> ...)), > > which would work unless anyone would want to use `fold*` itself in any > higher-order context (are there any use cases for that?). Perhaps higher-order folds are usually done by packaging the lower-level ones into library procedures, so the inner fold is an implementation detail that is not visible to the outer one. > Alternatively, `fold*` is an ordinary higher-order procedure receiving > a procedure that evaluates into another procedure first, e.g. like the > following or similarly: > > (fold* (lambda <list-formals> (lambda <seed-formals> body)) (lambda () > (values <seed> ...)) <list> ...) Would it work to use m-v boxes instead (as an abstraction built specifically for the purpose)? > Or we could restrict `fold*` to a single list, but this would restrict > its usefulness. We should probably have that one in any case. (fold* (lambda (elem acc1 acc2) ... (values new-acc1 new-acc2)) list init1 init2) is useful and quite easy to understand. > I would love to hear your suggestions, especially about further > procedures and syntax that should be included. You nicely covered all of the essentials :)