From: "Pascal J. Bourguignon" <pjb@informatimago.com>
To: emacs-devel@gnu.org
Subject: Re: Sweeter Emacs Lisp
Date: Sat, 10 Aug 2013 12:08:05 +0200 [thread overview]
Message-ID: <8761vdoo3e.fsf@informatimago.com> (raw)
In-Reply-To: 8738r5zyap.fsf@zigzag.favinet
Thien-Thi Nguyen <ttn@gnu.org> writes:
> () Stefan Monnier <monnier@iro.umontreal.ca>
> () Mon, 22 Jul 2013 17:04:04 -0400
>
> > RMS suggested instead:
> > (cond VAR (CONDITION [BODY...])
> > ...)
>
> As I pointed out back then, a more general solution is a way to
> let-bind new variables in between cond clauses, as in
>
> (cond
> (<test1> <body1>)
> (let x <foo>)
> (<test2> <body2>))
>
> which would be used in cases where we currently use
>
> (let (x)
> (cond
> (<test1> <body1>)
> ((progn (setq x <foo>) <test2>) <body2>))
I don't like it. The general idiom in lisp, and including in emacs
lisp, is to have a close correspondance between parentheses and lexical
scope.
Whether x is in the englobing scope, or in a scope covering only the
remaining clauses, in both cases it's bad because it's not reflected by
the sexp structure of the form.
In this aspect, RMS' suggestion is better.
I would advise a form rather like:
(letcond
((f) 1)
(let* ((x (g))
(y (h x)))
((= x y) 2)
((< x y) 3)
(let ((z (p)))
((< x z) 4))
(t 5))
((q) 6)
(t 0))
(defun letcond-generate-let-clause (let-clause)
(destructuring-bind (let bindings &body body) let-clause
`((,let ,bindings (cond ,@(letcond-generate-cond-clauses body))))))
(defun letcond-generate-cond-clauses (clauses)
(mapcar (lambda (clause)
(if (member (first clause) '(let let*))
(letcond-generate-let-clause clause)
clause))
clauses))
(defmacro letcond (&rest clauses)
`(cond ,@(letcond-generate-cond-clauses clauses)))
(pprint (macroexpand-1 '(letcond
((f) 1)
(let* ((x (g))
(y (h x)))
((= x y) 2)
((< x y) 3)
(let ((z (p)))
((< x z) 4))
(t 5))
((q) 6)
(t 0))))
--> (cond
((f) 1)
((let*
((x (g)) (y (h x)))
(cond
((= x y) 2)
((< x y) 3)
((let
((z (p)))
(cond ((< x z) 4))))
(t 5))))
((q) 6)
(t 0))
Notice how emacs already knows how to indent it to show the correct
scopes!
Yes, within a letcond, let and let* take another meaning (they are
interpreted specially by the letcond macro) when in the place of a
clause condition. In general I dislike those overloading, but I think
in this case it may be acceptable and the best solution, even if it
prevents you to use a variable named let or let*; you can always use
cond to test such a variable, or use (identity let):
(letcond
(let ((let 'let))
((identity let) let)
(t nil)))
--> let
vs. the surprizing:
(letcond
(let ((let 'let))
(let nil)
(t let)))
--> let
(letcond
(let ((let 'let))
(let let)
(t nil)))
Debugger entered--Lisp error: (wrong-type-argument sequencep let)
--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.
You know you've been lisping too long when you see a recent picture of George
Lucas and think "Wait, I thought John McCarthy was dead!" -- Dalek_Baldwin
next prev parent reply other threads:[~2013-08-10 10:08 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-07-14 2:22 Sweeter Emacs Lisp fgallina
2013-07-14 11:36 ` Dmitry Gutov
2013-07-14 11:53 ` Vitalie Spinu
2013-07-14 12:38 ` Aurélien Aptel
2013-07-14 13:25 ` Xue Fuqiao
2013-07-14 14:16 ` Pascal J. Bourguignon
2013-07-14 14:22 ` Lars Magne Ingebrigtsen
2013-07-14 16:27 ` Juanma Barranquero
2013-07-14 19:43 ` Lars Magne Ingebrigtsen
2013-07-15 3:20 ` Dmitry Gutov
2013-07-15 5:03 ` Stephen J. Turnbull
2013-07-16 20:23 ` Dmitry Gutov
2013-07-17 14:04 ` Lars Magne Ingebrigtsen
2013-07-17 15:07 ` Dmitry Gutov
2013-07-16 2:15 ` Miles Bader
2013-07-16 9:12 ` Stefan Monnier
2013-07-14 16:18 ` Josh
2013-07-14 16:30 ` Juanma Barranquero
2013-07-14 17:14 ` Josh
2013-07-14 17:18 ` Juanma Barranquero
2013-07-15 6:05 ` Lars Brinkhoff
2013-07-15 7:04 ` Stefan Monnier
2013-07-15 13:30 ` Bozhidar Batsov
2013-07-16 2:26 ` Miles Bader
2013-07-16 6:08 ` Thien-Thi Nguyen
2013-07-16 14:07 ` Drew Adams
2013-07-16 9:11 ` Stefan Monnier
2013-07-14 17:24 ` Andreas Schwab
2013-07-16 2:13 ` Miles Bader
2013-07-16 6:14 ` Stephen J. Turnbull
2013-07-16 9:07 ` Stefan Monnier
2013-07-16 11:09 ` Juanma Barranquero
2013-07-16 12:25 ` Andreas Schwab
2013-07-16 13:04 ` Thierry Volpiatto
2013-07-16 13:42 ` Juanma Barranquero
2013-07-16 14:38 ` Andreas Schwab
2013-07-16 14:42 ` Juanma Barranquero
2013-07-16 20:57 ` Stefan Monnier
2013-07-22 15:24 ` Stefan Monnier
2013-07-22 16:33 ` Thien-Thi Nguyen
2013-07-22 21:04 ` Stefan Monnier
2013-07-23 4:37 ` Thien-Thi Nguyen
2013-08-10 2:52 ` Stefan Monnier
2013-08-10 10:08 ` Pascal J. Bourguignon [this message]
2013-08-10 16:27 ` Drew Adams
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8761vdoo3e.fsf@informatimago.com \
--to=pjb@informatimago.com \
--cc=emacs-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).