* Re: Better documentation for non-binding clauses of if-let and friends
@ 2024-11-11 9:28 arthur miller
2024-11-11 9:58 ` Alfred M. Szmidt
0 siblings, 1 reply; 10+ messages in thread
From: arthur miller @ 2024-11-11 9:28 UTC (permalink / raw)
To: Alfred M. Szmidt, emacs-devel@gnu.org
[-- Attachment #1: Type: text/plain, Size: 1368 bytes --]
> I rather agree with Joost on that other thread regarding the
> usefulness of the FOO-let macros and their condition-only,
> non-binding clauses.
>
>I don't think anyone is arguing about their usefulness, only that the
>macros are too smart for their own good.
I think I will start argue against while-let usefulness :).
Now when I have seen that while-let is a special case of named-let,
I think that while-let is a bad construct for some reasons:
1. it is not general
2. the special case in which it does not work is hidden
3. the semantic of "read-only" loop variables is uncommon and unexpected
> > There is no mention of this in the manual, that only says that SPEC is
> > like the one in LET*.
That is the gotcha that got me: it says SPEC is "like let*", so this "-let*"
in the name take my mind to believe it established ordinary let*-bindings.
However, in while-let, these are not ordinary, but read-only. So they are
not the same, since they don't obey the ordinary behavior of let* bindings.
> But I agree with you that the manual is incomplete or even
> wrong here.
If that semantic of while-let is desirable to have, than the manual would
have to catch the details of while-let and its non-general nature, read-only
semantic of bindings and perhaps mention the named-let as a more general
alternative.
[-- Attachment #2: Type: text/html, Size: 5172 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Better documentation for non-binding clauses of if-let and friends
2024-11-11 9:28 Better documentation for non-binding clauses of if-let and friends arthur miller
@ 2024-11-11 9:58 ` Alfred M. Szmidt
2024-11-11 10:23 ` Sv: " arthur miller
2024-11-11 10:26 ` Joost Kremers
0 siblings, 2 replies; 10+ messages in thread
From: Alfred M. Szmidt @ 2024-11-11 9:58 UTC (permalink / raw)
To: arthur miller; +Cc: emacs-devel
That is the gotcha that got me: it says SPEC is "like let*", so this "-let*"
in the name take my mind to believe it established ordinary let*-bindings.
However, in while-let, these are not ordinary, but read-only. So they are
not the same, since they don't obey the ordinary behavior of let* bindings.
I agree, but the question really is what should be done -- either
satisfy one camp or the other.
I personally do not get what one gets from using WHILE-LET -- the
construct seems forced, and very rare to use.
IF-LET, WHEN-LET I can maybe guess but they too seem force constructs,
and why isn't there a UNLESS-LET and OR-LET*? But I'll leave it at
that, personal preferences and all.
> But I agree with you that the manual is incomplete or even
> wrong here.
If that semantic of while-let is desirable to have, than the manual would
have to catch the details of while-let and its non-general nature, read-only
semantic of bindings and perhaps mention the named-let as a more general
alternative.
Yup.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Sv: Better documentation for non-binding clauses of if-let and friends
2024-11-11 9:58 ` Alfred M. Szmidt
@ 2024-11-11 10:23 ` arthur miller
2024-11-11 10:26 ` Joost Kremers
1 sibling, 0 replies; 10+ messages in thread
From: arthur miller @ 2024-11-11 10:23 UTC (permalink / raw)
To: Alfred M. Szmidt; +Cc: emacs-devel@gnu.org
[-- Attachment #1: Type: text/plain, Size: 932 bytes --]
> That is the gotcha that got me: it says SPEC is "like let*", so this "-let*"
> in the name take my mind to believe it established ordinary let*-bindings.
> However, in while-let, these are not ordinary, but read-only. So they are
> not the same, since they don't obey the ordinary behavior of let* bindings.
>
>I agree, but the question really is what should be done -- either
>satisfy one camp or the other.
My guess is while-let can't go away since it is used in many places in Emacs
already. But the docs and the manual can be updated and clarified.
>I personally do not get what one gets from using WHILE-LET -- the
>construct seems forced, and very rare to use.
With the facit in the hand, I agree with you. In practice it saves some typing
in well-chosen contexts. But question is if it is a good practice to have a
construct that seemingly looks like a general let-construct, but really is not.
[-- Attachment #2: Type: text/html, Size: 3145 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Better documentation for non-binding clauses of if-let and friends
2024-11-11 9:58 ` Alfred M. Szmidt
2024-11-11 10:23 ` Sv: " arthur miller
@ 2024-11-11 10:26 ` Joost Kremers
2024-11-11 10:53 ` Sv: " arthur miller
2024-11-11 21:21 ` [External] : " Drew Adams
1 sibling, 2 replies; 10+ messages in thread
From: Joost Kremers @ 2024-11-11 10:26 UTC (permalink / raw)
To: Alfred M. Szmidt; +Cc: arthur miller, emacs-devel
On Mon, Nov 11 2024, Alfred M. Szmidt wrote:
> IF-LET, WHEN-LET I can maybe guess but they too seem force constructs,
I just recently wrote a simple RDP that has a couple of functions of this
form:
```
(if-let* (((parsebib--char "@"))
((parsebib--keyword '("string")))
(open (parsebib--char "{("))
(definition (parsebib--assignment))
((parsebib--char (alist-get open '((?\{ . "}") (?\( . ")"))))))
definition
(signal 'parsebib-error (list (format "Malformed @String definition at position %d,%d"
(line-number-at-pos) (current-column)))))
```
This reads a complete BibTeX @String definition. The clauses in the
`if-let*` specify what text should be read, and I can capture the result of
those reads, but only for the parts that I need to capture.
I think once you know how `if-let*` works, this is a fairly concise and
quite readable way to code this rule. Not sure what the equivalent without
`if-let*` would look like, TBH. (Short of creating a DSL, which would
admittedly be nicer...)
--
Joost Kremers
Life has its moments
^ permalink raw reply [flat|nested] 10+ messages in thread
* Sv: Better documentation for non-binding clauses of if-let and friends
2024-11-11 10:26 ` Joost Kremers
@ 2024-11-11 10:53 ` arthur miller
2024-11-11 11:18 ` Joost Kremers
2024-11-11 21:21 ` [External] : " Drew Adams
1 sibling, 1 reply; 10+ messages in thread
From: arthur miller @ 2024-11-11 10:53 UTC (permalink / raw)
To: Joost Kremers, Alfred M. Szmidt; +Cc: emacs-devel@gnu.org
[-- Attachment #1: Type: text/plain, Size: 1397 bytes --]
>I just recently wrote a simple RDP that has a couple of functions of this
>form:
>
>```
>(if-let* (((parsebib--char "@"))
> ((parsebib--keyword '("string")))
> (open (parsebib--char "{("))
> (definition (parsebib--assignment))
> ((parsebib--char (alist-get open '((?\{ . "}") (?\( . ")"))))))
> definition
> (signal 'parsebib-error (list (format "Malformed @String definition at position %d,%d"
> (line-number-at-pos) (current-column)))))
>```
>
>This reads a complete BibTeX @String definition. The clauses in the
>`if-let*` specify what text should be read, and I can capture the result of
>those reads, but only for the parts that I need to capture.
>
>I think once you know how `if-let*` works, this is a fairly concise and
>quite readable way to code this rule. Not sure what the equivalent without
>`if-let*` would look like, TBH. (Short of creating a DSL, which would
>admittedly be nicer...)
In my opinion, if-let and when-let are no brainer. they are actualy useful as a
synctatic-sugar and help keep variables in the scope of ift- and when-let. Those
bindings are usable as ordinary let-bindings, since they are established only once.
Problem is when one introduce repetition: while-let re-establishes the bindings a new
for each repetition, which is a bit unusual I believe.
[-- Attachment #2: Type: text/html, Size: 5037 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Sv: Better documentation for non-binding clauses of if-let and friends
2024-11-11 10:53 ` Sv: " arthur miller
@ 2024-11-11 11:18 ` Joost Kremers
0 siblings, 0 replies; 10+ messages in thread
From: Joost Kremers @ 2024-11-11 11:18 UTC (permalink / raw)
To: arthur miller; +Cc: Alfred M. Szmidt, emacs-devel@gnu.org
On Mon, Nov 11 2024, arthur miller wrote:
> Problem is when one introduce repetition: while-let re-establishes the bindings a new
> for each repetition, which is a bit unusual I believe.
I agree it's not immediately obvious, especially if you're trying to grok
`while-let` on the basis of `while`, so it should definitely be pointed out
in the documentation in the manual and the doc string, which currently
isn't the case.
It might be more obvious if you take `let` as your starting point for
grokking `while-let`, but then the non-binding forms can be confusing. So
that should be mentioned more explicitly as well, I think.
I do think reestablishing the bindings on each iteration makes sense, given
the purpose of `while-let`. I don't think it would be a very useful macro
if it were otherwise. But I have to admit I haven't yet had any occasion to
use `while-let`, and I haven't studied it in the wild, so I can't be
entirely sure. (Though I imagine that inside the loop, you would want to
use the *current* value of each of the conditions, not the value
established on the first iteration.)
--
Joost Kremers
Life has its moments
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [External] : Re: Better documentation for non-binding clauses of if-let and friends
2024-11-11 10:26 ` Joost Kremers
2024-11-11 10:53 ` Sv: " arthur miller
@ 2024-11-11 21:21 ` Drew Adams
2024-11-11 22:51 ` Joost Kremers
1 sibling, 1 reply; 10+ messages in thread
From: Drew Adams @ 2024-11-11 21:21 UTC (permalink / raw)
To: Joost Kremers, Alfred M. Szmidt; +Cc: arthur miller, emacs-devel@gnu.org
> (if-let* (((parsebib--char "@"))
> ((parsebib--keyword '("string")))
> (open (parsebib--char "{("))
> (definition (parsebib--assignment))
> ((parsebib--char (alist-get open '((?\{ . "}") (?\( . ")"))))))
> definition
> (signal 'parsebib-error
> (list (format "Malformed @String definition at position %d,%d"
> (line-number-at-pos) (current-column)))))
...
> Not sure what the equivalent without `if-let*` would look like, TBH.
Just `macroexpand' it, to see one equivalent, at least:
(let* ((s (and t (parsebib--char "@")))
(s (and s (parsebib--keyword '("string"))))
(open (and s (parsebib--char "{(")))
(definition (and open (parsebib--assignment)))
(s (and definition (parsebib--char
(alist-get open '((123 . "}") (40 . ")")))))))
(if s
definition
(signal 'parsebib-error
(list (format "Malformed @String definition at position %d,%d"
(line-number-at-pos) (current-column))))))
Or just this, if hand-coding (but you'd use a better name than `s'):
(let*((open (and (parsebib--char "@")
(parsebib--keyword '("string"))
(parsebib--char "{(")))
(definition (and open (parsebib--assignment)))
(s (and definition
(parsebib--char
(alist-get open '((123 . "}") (40 . ")")))))))
(if s
definition
(signal 'parsebib-error
(list (format "Malformed @String definition at position %d,%d"
(line-number-at-pos) (current-column))))))
Did you really gain anything? Debatable.
If you replace newline and multiple space runs with
just a single space then you can compare the if-let*
with the let* sexp above:
if-let*: 335 chars
let* : 369 chars (+ a few, with name other than `s')
Beauty and clarity are in the eye of the beholder, of
course. YMMV.
But at least the plain let* doesn't require or invite
a long discussion about what's really going on, as in
this thread and its siblings.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [External] : Re: Better documentation for non-binding clauses of if-let and friends
2024-11-11 21:21 ` [External] : " Drew Adams
@ 2024-11-11 22:51 ` Joost Kremers
2024-11-12 0:26 ` Drew Adams
0 siblings, 1 reply; 10+ messages in thread
From: Joost Kremers @ 2024-11-11 22:51 UTC (permalink / raw)
To: Drew Adams; +Cc: Alfred M. Szmidt, arthur miller, emacs-devel@gnu.org
On Mon, Nov 11 2024, Drew Adams wrote:
> (let*((open (and (parsebib--char "@")
> (parsebib--keyword '("string"))
> (parsebib--char "{(")))
> (definition (and open (parsebib--assignment)))
> (s (and definition
> (parsebib--char
> (alist-get open '((123 . "}") (40 . ")")))))))
> (if s
> definition
> (signal 'parsebib-error
> (list (format "Malformed @String definition at position %d,%d"
> (line-number-at-pos) (current-column))))))
[...]
> Beauty and clarity are in the eye of the beholder, of
> course. YMMV.
Yeah, I'm afraid I prefer the `if-let*` version. IMHO it more closely
reflects the parser grammar rule; it avoids unnecessary repetition of
variables (`open` and `definition` here) and the `and` forms that I feel
just obscure what's actually relevant.
--
Joost Kremers
Life has its moments
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [External] : Re: Better documentation for non-binding clauses of if-let and friends
2024-11-11 22:51 ` Joost Kremers
@ 2024-11-12 0:26 ` Drew Adams
2024-11-12 8:07 ` Joost Kremers
0 siblings, 1 reply; 10+ messages in thread
From: Drew Adams @ 2024-11-12 0:26 UTC (permalink / raw)
To: Joost Kremers; +Cc: Alfred M. Szmidt, arthur miller, emacs-devel@gnu.org
> > (let*((open (and (parsebib--char "@")
^^^^1
> > (parsebib--keyword '("string"))
> > (parsebib--char "{(")))
> > (definition (and open (parsebib--assignment)))
^^^^^^^^^^1 ^^^^2
> > (s (and definition
^^^^^^^^^^2
> > (parsebib--char
> > (alist-get
> > open '((123 . "}") (40 . ")")))))))
^^^^3
> > (if s
> > definition
^^^^^^^^^^3
> > (signal 'parsebib-error
> > (list (format "Malformed @String definition at position %d,%d"
> > (line-number-at-pos) (current-column))))))
> [...]
>
> > Beauty and clarity are in the eye of the beholder, of
> > course. YMMV.
>
> Yeah, I'm afraid I prefer the `if-let*` version.
NP. Les goûts et les couleurs.
> IMHO it more closely
> reflects the parser grammar rule; it avoids unnecessary repetition of
> variables (`open` and `definition` here) and the `and` forms that I feel
> just obscure what's actually relevant.
It avoids one repetition each of vars `open' and
`definition'. Those occurrences make explicit
the `and' dependencies implicit in `if-let*
(necessary/relevant dependencies).
This is your if-let*, with space separation of
bindings from conditions:
> (if-let* (( (parsebib--char "@"))
> ( (parsebib--keyword '("string")))
> (open (parsebib--char "{("))
^^^^1
> (definition (parsebib--assignment))
^^^^^^^^^^1
> ( (parsebib--char
(alist-get
open '((?\{ . "}") (?\( . ")"))))))
^^^^2
> definition
^^^^^^^^^^2
> (signal 'parsebib-error
> (list (format "Malformed @String definition at position %d,%d"
> (line-number-at-pos) (current-column)))))
Implied and-ing is all the if-let* gets you, at
least in this example. At the cost of a loss of
obvious distinction between binding and use
occurrences.
I guess your parser grammar rule (not shown) just
has the (parsebib-*...) conditions as literal
match patterns, and it has `open' and `definition'
as nonterminals. (Or maybe `definition' is a
terminal, since you return that.)
In any case, you said you didn't know what an
"equivalent without `if-let*` would look like".
So I mentioned that `macroexpand' has the answer.
And the answer isn't very complex. In this case,
at least, it just makes the and-ing of binding
dependencies explicit/clear.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [External] : Re: Better documentation for non-binding clauses of if-let and friends
2024-11-12 0:26 ` Drew Adams
@ 2024-11-12 8:07 ` Joost Kremers
0 siblings, 0 replies; 10+ messages in thread
From: Joost Kremers @ 2024-11-12 8:07 UTC (permalink / raw)
To: Drew Adams; +Cc: Alfred M. Szmidt, arthur miller, emacs-devel@gnu.org
On Tue, Nov 12 2024, Drew Adams wrote:
> This is your if-let*, with space separation of
> bindings from conditions:
>
>> (if-let* (( (parsebib--char "@"))
>> ( (parsebib--keyword '("string")))
>> (open (parsebib--char "{("))
> ^^^^1
>> (definition (parsebib--assignment))
> ^^^^^^^^^^1
>> ( (parsebib--char
> (alist-get
> open '((?\{ . "}") (?\( . ")"))))))
> ^^^^2
>> definition
> ^^^^^^^^^^2
>> (signal 'parsebib-error
>> (list (format "Malformed @String definition at position %d,%d"
>> (line-number-at-pos) (current-column)))))
>
> Implied and-ing is all the if-let* gets you, at
> least in this example. At the cost of a loss of
> obvious distinction between binding and use
> occurrences.
I don't see the loss. The `if-let*` version has two occurrences of `open`
and `definition`: the first is the binding, the second is the use. Without
`if-let*`, I need to repeat both once more to test if they're non-nil.
Those occurrences and the `and`s are there to make the code do what I want,
but they don't help express the idea behind the code, so to my mind they're
boilerplate.
> I guess your parser grammar rule (not shown) just
> has the (parsebib-*...) conditions as literal
> match patterns, and it has `open' and `definition'
> as nonterminals.
`post` is also a literal, I'm just capturing it so I can make sure I get
the corresponding closing delimiter. Otherwise you could close a curly
brace { with a parenthesis ) or vice versa. (Yes, this is cheating, I
know...) `definition` is a non-terminal (and should probably be called
`assignment`).
> In any case, you said you didn't know what an
> "equivalent without `if-let*` would look like".
> So I mentioned that `macroexpand' has the answer.
True, it didn't occur to me to look at it.
> And the answer isn't very complex. In this case,
> at least, it just makes the and-ing of binding
> dependencies explicit/clear.
Which I feel is unnecessary and even a hindrance.
--
Joost Kremers
Life has its moments
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2024-11-12 8:07 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-11 9:28 Better documentation for non-binding clauses of if-let and friends arthur miller
2024-11-11 9:58 ` Alfred M. Szmidt
2024-11-11 10:23 ` Sv: " arthur miller
2024-11-11 10:26 ` Joost Kremers
2024-11-11 10:53 ` Sv: " arthur miller
2024-11-11 11:18 ` Joost Kremers
2024-11-11 21:21 ` [External] : " Drew Adams
2024-11-11 22:51 ` Joost Kremers
2024-11-12 0:26 ` Drew Adams
2024-11-12 8:07 ` Joost Kremers
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).