The most general form of let/let* Marc Nieper-Wißkirchen (15 Nov 2022 12:30 UTC)
Re: The most general form of let/let* Lassi Kortela (15 Nov 2022 20:11 UTC)
Re: The most general form of let/let* Lassi Kortela (15 Nov 2022 20:23 UTC)
Re: The most general form of let/let* Marc Nieper-Wißkirchen (15 Nov 2022 20:28 UTC)
Re: The most general form of let/let* John Cowan (15 Nov 2022 20:38 UTC)
Re: The most general form of let/let* Marc Nieper-Wißkirchen (15 Nov 2022 20:48 UTC)
Re: The most general form of let/let* Daphne Preston-Kendal (15 Nov 2022 20:35 UTC)
Re: The most general form of let/let* Marc Nieper-Wißkirchen (15 Nov 2022 20:43 UTC)
Re: The most general form of let/let* Lassi Kortela (16 Nov 2022 08:19 UTC)
Re: The most general form of let/let* Jeremy Steward (17 Nov 2022 01:53 UTC)
Re: The most general form of let/let* Marc Nieper-Wißkirchen (17 Nov 2022 07:49 UTC)
Re: The most general form of let/let* Jeremy Steward (17 Nov 2022 02:11 UTC)
Re: The most general form of let/let* Marc Nieper-Wißkirchen (17 Nov 2022 07:55 UTC)
Re: The most general form of let/let* Lassi Kortela (17 Nov 2022 08:01 UTC)

Re: The most general form of let/let* Daphne Preston-Kendal 15 Nov 2022 20:35 UTC

I file improvements like this to let under ‘things we’d do differently if we did Scheme again from scratch, but it’s too late now’.

Personally I’d have three forms: let (which would be what we currently call letrec*), recur (which would be what we currently call named let), and let-syntax (which would be what we currently call letrec-syntax).

The explosion of near-identical let forms, and the need to nest them sometimes, is a wart, but adding more just creates an xkcd 927 situation.

Daphne

> On 15 Nov 2022, at 13:30, Marc Nieper-Wißkirchen <xxxxxx@nieper-wisskirchen.de> wrote:
>
> In Scheme, we use the `let' construct when we want our interpreter to
> perform several independent operations, and we are interested in the
> return values of these operations.
>
> If, on the other hand, the operations depend on the results (let us
> neglect side effects, which also create dependencies) of previous
> operations, we use the `let*' construct.
>
> Often, however, the most abstract representation of the algorithm we
> want to code would need a mixture of `let' and `let*' forms.  Consider
> the following example:
>
> (let* ((a (f))
>        (b (g))
>        (c (h b))
>        (d (k c)))
>  <body>)
>
> Here, D depends on C, which depends on B.  So
>
> (let ((a (f))
>       (b (g)))
>  (let* ((c (h b))
>          (d (k c)))
>    <body>))
>
> is a rewrite that is closer to the actual dependency graph.  But it is
> still not an accurate image of the platonic idea.  In particular,
>
> (let ((b (g)))
>  (let* ((c (h b))
>          (d (k c)))
>    (let ((a (f)))
>      <body>)))
>
> is a different approximation, which like the other two, still does not
> capture the idea that the binding to A is independent of the other
> bindings.
>
> So, a way to express a general dependency graph is needed and let the
> Scheme interpreter sort out a suitable sequencing.
>
> I propose a form like the following one:
>
> (let-values (((d) (using c
>                            (k c)))
>                   ((a) (f))
>                   ((c) (using b
>                            (h b)))
>                   ((b) (g)))
>  <expr>)
>
> Marc
>
> “The purpose of abstracting is not to be vague, but to create a new
> semantic level in which one can be absolutely precise.”
> ― Edsger W. Dijkstra