Subject: bug#49407: Request: Specify default values in `map-let` in Map.el

From: Michael Heerdegen <[email-masked]>
Date: Sat, 22 Jul 2023 03:48:03 +0200

Okam <[email-masked]> writes:

> I've written a patch and tests that would add an optional third
> argument for a default value.

Thank you.

> However, I have a question about avoiding using a lambda. I see that
> the pattern uses `pcase--flip`, which is "used internally to avoid
> (funcall (lambda ...) ...)". Why should lambda functions be avoided
> for this,

As far as I understand, to produce more efficient code.

> and I should be using a custom helper function for this one pattern?

Stefan, would you want to extend `pcase--flip' to more arguments to
support this case?

| diff --git a/lisp/emacs-lisp/map.el b/lisp/emacs-lisp/map.el
| index 7a48ba47434..7f127f312de 100644
| --- a/lisp/emacs-lisp/map.el
| +++ b/lisp/emacs-lisp/map.el
| @@ -50,18 +50,23 @@ map
|
|  ARGS is a list of elements to be matched in the map.
|
| -Each element of ARGS can be of the form (KEY PAT), in which case KEY is
| -evaluated and searched for in the map.  The match fails if for any KEY
| -found in the map, the corresponding PAT doesn't match the value
| -associated with the KEY.
| +Each element of ARGS can be of the form (KEY PAT) or (KEY PAT DEFAULT),
| +
| +in which case KEY is evaluated and searched for in the map and

That line break in the last sentence is somehow... broken.

| +DEFAULT is the evaluated value used if KEY is not found.  The
| +match fails if for any KEY found in the map, the corresponding
| +PAT doesn't match the value associated with the KEY.  The match
| +fails if for any KEY not found in the map, the corresponding PAT
| +doesn't match the DEFAULT value, if given.

Here is something grammatically not right in the last sentence.  And I
think we should say that that last case (PAT doesn't match DEFAULT) only
lets matching fail when the KEY is not found.

| -Keys in ARGS not found in the map are ignored, and the match doesn't
| -fail."
| +When no DEFAULT value is given, the default value for keys in
| +ARGS not found in the map is nil, and the match doesn't fail so
| +long at PAT, if given, matches nil."
|    `(and (pred mapp)
|          ,@(map--make-pcase-bindings args)))

Typo in doc ("at").  And can't we simply say that omitting DEFAULT is
equivalent to a DEFAULT of nil?

| @@ -599,7 +606,11 @@ map--make-pcase-bindings
|    "Return a list of pcase bindings from ARGS to the elements of a map."
|    (mapcar (lambda (elt)
|              (cond ((consp elt)
| -                   `(app (pcase--flip map-elt ,(car elt)) ,(cadr elt)))
| +                   (if (cddr elt)
| +                       `(app (lambda (arg)
| +                               (map-elt arg ,(car elt) ,(caddr elt)))
| +                             ,(cadr elt))
| +                     `(app (pcase--flip map-elt ,(car elt)) ,(cadr elt))))

If we don't extend `pcase--flip' to support this case, I think your
lambda would need to use an uninterned symbol as parameter to avoid
collisions with the involved expressions.

Michael.