From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.devel Subject: pcase pattern syntax (was: Replace trivial pcase occurrences in the Emacs sources) Date: Wed, 24 Oct 2018 09:03:51 -0400 Message-ID: References: <87oad2irtd.fsf@fencepost.gnu.org> <5689456A.1010601@yandex.ru> <87egdy8tyz.fsf@fencepost.gnu.org> <56895FDE.4060406@yandex.ru> <8760za8r4a.fsf@fencepost.gnu.org> <87h9iunkcg.fsf@web.de> <87h8hc4xw2.fsf_-_@web.de> <83tvlcsnee.fsf@gnu.org> <20181024083423.GA13100@Swift> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit X-Trace: blaine.gmane.org 1540387168 8688 195.159.176.226 (24 Oct 2018 13:19:28 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Wed, 24 Oct 2018 13:19:28 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Wed Oct 24 15:19:24 2018 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1gFJ4G-00029e-5i for ged-emacs-devel@m.gmane.org; Wed, 24 Oct 2018 15:19:24 +0200 Original-Received: from localhost ([::1]:48358 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gFJ6M-0002bU-Kv for ged-emacs-devel@m.gmane.org; Wed, 24 Oct 2018 09:21:34 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:49531) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gFJ51-0000ZX-Sy for emacs-devel@gnu.org; Wed, 24 Oct 2018 09:20:15 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gFIpV-0001cY-CA for emacs-devel@gnu.org; Wed, 24 Oct 2018 09:04:15 -0400 Original-Received: from [195.159.176.226] (port=48136 helo=blaine.gmane.org) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1gFIpT-0001Yu-Fr for emacs-devel@gnu.org; Wed, 24 Oct 2018 09:04:09 -0400 Original-Received: from list by blaine.gmane.org with local (Exim 4.84_2) (envelope-from ) id 1gFInF-0005bR-NH for emacs-devel@gnu.org; Wed, 24 Oct 2018 15:01:49 +0200 X-Injected-Via-Gmane: http://gmane.org/ Original-Lines: 111 Original-X-Complaints-To: usenet@blaine.gmane.org Cancel-Lock: sha1:L6Kd5OEFnmzKXs175pLLFxOrZmg= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 195.159.176.226 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:230623 Archived-At: > (pcase value > (`(,_ 1 2) > (message "Matched a list of anything followed by (1 2)"))) > > It is not clear to me why I couldn't simply write: > > (pcase value > ((_ 1 2) > (message "Matched a list of anything followed by (1 2)"))) The reason is simple: because pcase uses a more verbose pattern syntax. There are many different choices for pattern syntax, with various tradeoffs between conciseness, regularity, and extensibility. pcase's syntax leans in favor of regularity and extensibility to the detriment of conciseness. In your above example, if you allow (_ 1 2) to mean the same as pcase's `(,_ 1 2), then you need some special syntax for the case where you meant to match the same as pcase's '(_ 1 2). > would then match lists of the form (1 2 3 3), not (1 2 3 4). If you > need to bind multiple values, I could imagine using something like: > > (pcase value > ((1 2 %1 %2) > (message "Matched 1, 2, something now bound to %1, and something (else) bound to %2"))) that's getting pretty close to (1 2 ,x ,y): the only differences being the use of % instead of comma and the absence of a surrounding backquote. > why not write: > > ``` > (pcase value > ((1 2 (or 3 4) > (and (stringp %) > (string> "aaa" %) > (> (length %) 10))) > (message "Matched 1, 2, 3 or 4, and a long string " > "that is lexically greater than 'aaa'"))) Why wouldn't that be matching the same as pcase's (pcase value (`(1 2 (or 3 4) (and (stringp ,x) (string> "aaa" ,y) (> (length ,z) 10))) (message "Matched 1, 2, 3 or 4, and a long string " "that is lexically greater than 'aaa'"))) or alternatively, what special syntax would you introduce in order to say "this (or 3 4) shouldn't match "either 3 or 4" but should match a the 3-element list (or 3 4)"? > uses `(and foo (guard ...))' to bind a value to `foo' and apply > a predicate to it. That's a coding pattern that you need to be > familiar with in order to understand what it does. (John explains it > in his tutorial, but if I had met this in the wild, I'd probably be > puzzled by it at first). The % syntax would seem to make this simpler > as well: Yes, the and+guard thingy sucks. I've been thinking of changing `guard` so it automatically does an `and`, i.e. make it so that (guard foo EXP) is the same as (and foo (guard EXP)) but I don't find this terribly good either. Note that you can also write it as (pred (lambda (foo) EXP)) which is clearly not more friendly but I just mention it in case it might help someone come up with yet another solution. Many pattern matching systems don't have guards as part of the patterns and instead have them "on the side", in which case you'd write ... ,foo ... in the pattern and (guard EXP) elsewhere. I find this to be a nice way to solve the problem, but: - I don't know where to place this EXP. Maybe a branch could take the form (PATTERN :guard EXP BODY)? - This forces the guard expressions to be evaluated at the very end, so it's a bit less expressive. In practice this is not too bad, tho. - There's a similar problem for the (let PAT EXP) pattern, where it often/generally has to be coupled with an `and` as in (and PAT1 (let PAT EXP)), but this problem can't be solved by moving the `let` outside of the pattern like we can for the `guard`. > This example also shows that `and' has a meaning in pcase that is > subtly different from its usual meaning in Lisp: `and' in a pcase > 'UPattern' (as the manual calls it) is not a logical `and' in the > sense that it tests its arguments for truthiness. Rather, it means > «both arguments of `and' must apply to the value at this position > *regardless of truthiness*». (The `and' inside the guard does have the > usual meaning, of course.) That's right: the `and` pattern is really an intersection of patterns. Stefan