emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: pcase-setq


From: Stefan Monnier
Subject: Re: pcase-setq
Date: Wed, 14 Oct 2015 11:49:43 -0400
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.0.50 (gnu/linux)

> (Was it your intention not to CC emacs-dev?  Anyway, I respect it.)

No, I used "reply to all", but there was no emacs-devel in the Cc.
[...hmm...]
Oh, I see there was a "Newsgroups: gmane.emacs.devel" instead, so that's
apparently what caused the problem.

>> It seems to work, indeed.  It could misbehave if you use `guard'
>> or `pred' patterns, but it'd be weird to use them in a `pcase-setq' and
>> the misbehavior is fairly subtle, so I guess overall it's quite OK.
> I'm not sure it would always be weird to use them.  On the contrary, I
> would like that this works, like in (some fantasy example):
>
> --8<---------------cut here---------------start------------->8---
> (defun my-count-chars-in (thing)
>   (pcase-setq (or (and (pred stringp) (app length a))
>                   (and (pred numberp) (let a 1))
>                   (guard (error "No characters here to count")))
>               thing))
> --8<---------------cut here---------------end--------------->8---
>
> If it would not work, I would consider it a bug.

Indeed, having thought some more about it, I think it'll work OK.
I was thinking of cases like:

   (pcase-setq (or (and `(,a . ,b) (guard (> a b)))
                   (and (pred consp) (pred (car-less-than-car a))))
               thing)

where the value of `a' used in the pred could be affected by the
previous `a' setting for the guard, but the guard should still use
let-binding rather than setq AFAICT, so I think we're fine.

A more direct inconvenience is that `let' will be turned into a `setq':

  (pcase-setq (or (and a (pred numberp)) (let a 0)) x)

This is not too bad in the sense that it's useful behavior, but the
problem is in the clash between the name `let' used for that pattern and
the actual behavior.

>> Any chance you could directly hook this into gv.el so that we can
>> simply do (setf `(,a . ,b) ...) ?
> A far-reaching question!
> Do we really want to allow that anything accepts a generalized variable
> and a pcase pattern at the same time (your answer is obviously "yes").

Actually, no, I don't think 100% integration between the two makes much
sense: a GV is usually expected to denote a "place" where we can store
any value via side-effects whereas a pcase pattern usually denotes
a subset of possible values.

In other terms, a pcase pattern generally resembles a *constructor*, so
as to only accept values generated by this constructor and to extract
the arguments that were passed to this constructor.  IOW the pcase
takes a constructor and gives you the matching destructor.

Whereas a GV generally resembles a *destructor*, and its expander is
kind-of-like-but-not-really a way to get the matching constructor.

I don't think a generalized variable would make much sense in
a pcase statement.

But I think that the intersection of generalized-variables and pcase
patterns that can be used in pcase-setq is pretty much the empty-set
[ save for the dummy:

   ;;; Even more debatable extensions.
   (put 'cons 'gv-expander
        (lambda (do a d)
          (gv-letplace (agetter asetter) a
            (gv-letplace (dgetter dsetter) d
              (funcall do
                       `(cons ,agetter ,dgetter)
                       (lambda (v) `(progn
                                 ,(funcall asetter `(car ,v))
                                 ,(funcall dsetter `(cdr ,v)))))))))

that's in gv.el.  ]

so if doable, it would be nice to merge the pcase-setq functionality
into setf.

> in all cases?  With other words: Would it make sense that at any place
> in a pcase pattern where a symbol would be bound, an arbitrary place
> expression would be allowed, too?

Right, that'd be the natural way to mix the two: have them joined at the
place where the "select&extract" part of pcase is done and the "store
somewhere" of setf can start.

But note that it makes sense for pcase-setq since that's naturally
side-effecting but it makes much less sense for pcase-let or pcase.
For those, we'd need a `cl-letf' kind of semantics, IOW a dynamic
scoping semantics.

Also, I'm not convinced that it would be very useful.
I mean, yes, you could write

  (pcase-setq `(,(gethash k1 t) . ,(gethash k2 t)) <foo>)

but do we really want to go there?

So, yeah, maybe we're better off with a separate pcase-setq.


        Stefan



reply via email to

[Prev in Thread] Current Thread [Next in Thread]