* Sweeter Emacs Lisp
@ 2013-07-14 2:22 fgallina
2013-07-14 11:36 ` Dmitry Gutov
` (5 more replies)
0 siblings, 6 replies; 45+ messages in thread
From: fgallina @ 2013-07-14 2:22 UTC (permalink / raw)
To: emacs-devel
Hello all,
The last months I've been playing with Clojure[0] a lot, within its
primitives I found the following functionality exquisite and I think it
may be time for Emacs Lisp to evolve and provide similar stuff making
easier/more-fun to write code in it. Here's a detailed list with
examples of what I would want to see as part of core Emacs Lisp:
+ The *threading* macros "->" and "->>":
;; clojure.core/->
;; ([x] [x form] [x form & more])
;; Macro
;; Threads the expr through the forms. Inserts x as the
;; second item in the first form, making a list of it if it is not a
;; list already. If there are more forms, inserts the first form as the
;; second item in second form, etc.
(setq tag (cons "<p>" "</p>"))
(defun tag-desc (tag)
(concat (upcase (car tag)) "."))
(defun tag-desc-stripped (tag)
(upcase (replace-regexp-in-string "[<\\/> ]" "" (car tag))))
;; with threading macros
(defun tag-desc (tag)
(-> (car tag) (upcase) (concat ".")))
(defun tag-desc-strip (tag)
(->> (car tag) (replace-regexp-in-string "[<\\/> ]" "") (upcase)))
+ when-let, if-let:
;; clojure.core/when-let
;; ([bindings & body])
;; Macro
;; bindings => binding-form test
;; When test is true, evaluates body with binding-form bound to the value of test
;;-------------------------
;; clojure.core/if-let
;; ([bindings then] [bindings then else & oldform])
;; Macro
;; bindings => binding-form test
;; If test is true, evaluates then with binding-form bound to the value of
;; test, if not, yields else
(let ((pos (re-search-backward "regex" nil t)))
(when pos
(list pos (match-string-no-properties 0))))
(when-let ((pos (re-search-backward "regex" nil t)))
(list pos (match-string-no-properties 0)))
+ *we need a built-in core mapcan (could be called mapcat), filter and
sequence concatenation (could be called cat?) function that doesn't
depends on cl-lib*. This is fundamental stuff isn't it? Why is such a
need to require a library for it?
+ Destructuring in defun and let: This looks weirder than I thought
because of our (ab)use of parens everywhere, but I feel this is
something brillant to have as part of the core language.
;; http://clojure.org/special_forms#binding-forms
(setq tag (cons "<p>" "</p>"))
(defun fmt-tag (tag)
(let ((open (car tag))
(close (cdr tag)))
(format open close)))
;; defun destructuring
(defun fmt-tag ((open close))
(format open close))
;; let destructuring
(defun fmt-tag (tag)
(let (((open close) tag))
(format open close)))
+ make `let` work like `let*`: "let's" stop confusing newcomers.
+ hash-tables: how come that working with hash-tables is such a pain?
I love how they are function of themselves in clojure and that
there's reader syntax for them.
(setq tags (make-hash-table))
(puthash tags :p "</p>")
(puthash tags :span "</span>")
(gethash :span tags) ; -> "</p>"
;; clojuresque version
(setq tags {:p "</p>" :span "</span>"})
(:p tags) ; -> "</p>"
(tags :p) ; -> "</p>"
(:html tags) ; -> nil
(tags :html) ; -> signals error
;; Another option is just using the hash-table itself as a function
;; and don't signal an error if a third arg is provided as the
;; default.
(tags :html) ; -> signals error
(tags :html "<html>") ; -> "<html>"
This is a quick list from the top of my head but there's more (for
instance, cond with less parens and reader syntax for anonymous
functions), but I'd like to have some comments first WRT the
possibilities and acceptance.
My high level idea is that we'd have all this stuff in a single file and
my hope is that it could be implemented a such way that is compatible
with older versions of Emacs (say down to 22).
Users of older Emacs will just need to require this file in their .emacs
to use packages that use these new utilities, but in newer Emacs
releases, these things will be considered core stuff and no require will
be needed whatsoever.
I hope we can do some brainstorming a bit. My goal with this is to find
ways to evolve Emacs Lisp a bit further by providing facilities that
allow writting cleaner and more redeable code while allowing for
backwards compatibility.
[0] http://clojure.org/
--
Regards,
Fabián
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
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 14:22 ` Lars Magne Ingebrigtsen
` (4 subsequent siblings)
5 siblings, 1 reply; 45+ messages in thread
From: Dmitry Gutov @ 2013-07-14 11:36 UTC (permalink / raw)
To: fgallina; +Cc: emacs-devel
fgallina@gnu.org writes:
> Hello all,
>
> The last months I've been playing with Clojure[0] a lot, within its
> primitives I found the following functionality exquisite and I think it
> may be time for Emacs Lisp to evolve and provide similar stuff making
> easier/more-fun to write code in it. Here's a detailed list with
> examples of what I would want to see as part of core Emacs Lisp:
> ...
Have you looked at dash? It implements most of these.
https://github.com/magnars/dash.el/
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-14 11:36 ` Dmitry Gutov
@ 2013-07-14 11:53 ` Vitalie Spinu
2013-07-14 12:38 ` Aurélien Aptel
` (2 more replies)
0 siblings, 3 replies; 45+ messages in thread
From: Vitalie Spinu @ 2013-07-14 11:53 UTC (permalink / raw)
To: Dmitry Gutov; +Cc: fgallina, emacs-devel
>> Dmitry Gutov <dgutov@yandex.ru>
>> on Sun, 14 Jul 2013 15:36:52 +0400 wrote:
[...]
> Have you looked at dash? It implements most of these.
> https://github.com/magnars/dash.el/
Would be so nice if dash.el were in emacs proper.
Vitalie
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
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
2 siblings, 0 replies; 45+ messages in thread
From: Aurélien Aptel @ 2013-07-14 12:38 UTC (permalink / raw)
To: Vitalie Spinu; +Cc: fgallina, emacs-devel, Dmitry Gutov
On Sun, Jul 14, 2013 at 1:53 PM, Vitalie Spinu <spinuvit@gmail.com> wrote:
> Would be so nice if dash.el were in emacs proper.
It would be very nice indeed.
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
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
2 siblings, 0 replies; 45+ messages in thread
From: Xue Fuqiao @ 2013-07-14 13:25 UTC (permalink / raw)
To: Vitalie Spinu; +Cc: fgallina, emacs-devel, Dmitry Gutov
On Sun, Jul 14, 2013 at 7:53 PM, Vitalie Spinu <spinuvit@gmail.com> wrote:
> >> Dmitry Gutov <dgutov@yandex.ru>
> >> on Sun, 14 Jul 2013 15:36:52 +0400 wrote:
>
> [...]
>
>
> > Have you looked at dash? It implements most of these.
>
> > https://github.com/magnars/dash.el/
>
> Would be so nice if dash.el were in emacs proper.
Maybe even further:
http://lists.gnu.org/archive/html/emacs-devel/2013-06/msg01301.html
--
Best regards, Xue Fuqiao.
http://www.gnu.org/software/emacs/
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
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
2 siblings, 0 replies; 45+ messages in thread
From: Pascal J. Bourguignon @ 2013-07-14 14:16 UTC (permalink / raw)
To: emacs-devel
Vitalie Spinu <spinuvit@gmail.com> writes:
> >> Dmitry Gutov <dgutov@yandex.ru>
> >> on Sun, 14 Jul 2013 15:36:52 +0400 wrote:
>
> [...]
>
>
> > Have you looked at dash? It implements most of these.
>
> > https://github.com/magnars/dash.el/
>
> Would be so nice if dash.el were in emacs proper.
What difference would that make?
--
__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
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-14 2:22 Sweeter Emacs Lisp fgallina
2013-07-14 11:36 ` Dmitry Gutov
@ 2013-07-14 14:22 ` Lars Magne Ingebrigtsen
2013-07-14 16:27 ` Juanma Barranquero
` (2 more replies)
2013-07-14 16:18 ` Josh
` (3 subsequent siblings)
5 siblings, 3 replies; 45+ messages in thread
From: Lars Magne Ingebrigtsen @ 2013-07-14 14:22 UTC (permalink / raw)
To: fgallina; +Cc: emacs-devel
fgallina@gnu.org writes:
> + The *threading* macros "->" and "->>":
[...]
> (setq tag (cons "<p>" "</p>"))
>
> (defun tag-desc (tag)
> (concat (upcase (car tag)) "."))
>
> (defun tag-desc-stripped (tag)
> (upcase (replace-regexp-in-string "[<\\/> ]" "" (car tag))))
>
> ;; with threading macros
> (defun tag-desc (tag)
> (-> (car tag) (upcase) (concat ".")))
>
> (defun tag-desc-strip (tag)
> (->> (car tag) (replace-regexp-in-string "[<\\/> ]" "") (upcase)))
It's not clear what the point of these are. Just to make the code more
obscure and cool? The new forms (as demonstrated here) even leads to
longer code, in addition to being pretty opaque. While the "old" code
is obvious and easy to read.
> + when-let, if-let:
Yes, `when-let' is pretty nice.
> + *we need a built-in core mapcan (could be called mapcat), filter and
> sequence concatenation (could be called cat?) function that doesn't
> depends on cl-lib*. This is fundamental stuff isn't it? Why is such a
> need to require a library for it?
Why not just use the cl functions?
> + Destructuring in defun and let: This looks weirder than I thought
> because of our (ab)use of parens everywhere, but I feel this is
> something brillant to have as part of the core language.
Destructuring lambda argument lists (a la Common Lisp) would be very
nice, yes, but is probably an uphill battle.
> ;; let destructuring
> (defun fmt-tag (tag)
> (let (((open close) tag))
> (format open close)))
This is just a different way to write `destructuring-bind', though. I
don't see the point.
> + make `let` work like `let*`: "let's" stop confusing newcomers.
I don't think it's that confusing. It would be more confusing having
let and let* work differently in Emacs Lisp than in other Lisps, I
think.
> + hash-tables: how come that working with hash-tables is such a pain?
> I love how they are function of themselves in clojure and that
> there's reader syntax for them.
>
> (setq tags (make-hash-table))
> (puthash tags :p "</p>")
> (puthash tags :span "</span>")
> (gethash :span tags) ; -> "</p>"
That's painful? It seems clear and nice to me.
> ;; clojuresque version
> (setq tags {:p "</p>" :span "</span>"})
> (:p tags) ; -> "</p>"
> (tags :p) ; -> "</p>"
> (:html tags) ; -> nil
This just seems like a "neat" way to write opaque code. Did the Clojure
people come from a Perl or Scheme background, by any chance?
> [0] http://clojure.org/
If these are the bits that are exciting in Clojure, then Clojure doesn't
seem particularly exciting to me. :-)
--
(domestic pets only, the antidote for overdose, milk.)
bloggy blog http://lars.ingebrigtsen.no/
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-14 2:22 Sweeter Emacs Lisp fgallina
2013-07-14 11:36 ` Dmitry Gutov
2013-07-14 14:22 ` Lars Magne Ingebrigtsen
@ 2013-07-14 16:18 ` Josh
2013-07-14 16:30 ` Juanma Barranquero
2013-07-15 7:04 ` Stefan Monnier
2013-07-14 17:24 ` Andreas Schwab
` (2 subsequent siblings)
5 siblings, 2 replies; 45+ messages in thread
From: Josh @ 2013-07-14 16:18 UTC (permalink / raw)
To: fgallina; +Cc: emacs-devel
On Sat, Jul 13, 2013 at 7:22 PM, <fgallina@gnu.org> wrote:
> may be time for Emacs Lisp to evolve and provide similar stuff making
> easier/more-fun to write code in it. Here's a detailed list with
> examples of what I would want to see as part of core Emacs Lisp:
I made a related suggestion recently, see the thread at
http://lists.gnu.org/archive/html/emacs-devel/2013-06/msg01198.html.
> + when-let, if-let:
>
> ;; clojure.core/when-let
> ;; ([bindings & body])
> ;; Macro
> ;; bindings => binding-form test
> ;; When test is true, evaluates body with binding-form bound to the value of test
> ;;-------------------------
> ;; clojure.core/if-let
> ;; ([bindings then] [bindings then else & oldform])
> ;; Macro
> ;; bindings => binding-form test
> ;; If test is true, evaluates then with binding-form bound to the value of
> ;; test, if not, yields else
I'm not very familiar with Clojure but these appear to be available
already in the form of two anaphoric macros that ship with Emacs
(`ibuffer-awhen' and `ibuffer-aif'). Unfortunately, being tucked away
as they are in ibuf-macs.el (which is not loaded by default), anyone
looking for this functionality with `apropos' or `info-apropos' would
find nothing and conclude that they did not exist yet, and as a result
needlessly re-implement them herself or drag in another library.
> (let ((pos (re-search-backward "regex" nil t)))
> (when pos
> (list pos (match-string-no-properties 0))))
>
> (when-let ((pos (re-search-backward "regex" nil t)))
> (list pos (match-string-no-properties 0)))
(require 'ibuf-macs)
(ibuffer-awhen (re-search-backward "regex" nil t)
(list it (match-string-no-properties 0)))
Josh
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
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-16 2:15 ` Miles Bader
2 siblings, 1 reply; 45+ messages in thread
From: Juanma Barranquero @ 2013-07-14 16:27 UTC (permalink / raw)
To: Lars Magne Ingebrigtsen; +Cc: fgallina, emacs-devel
On Sun, Jul 14, 2013 at 4:22 PM, Lars Magne Ingebrigtsen <larsi@gnus.org> wrote:
> Why not just use the cl functions?
+1
> Destructuring lambda argument lists (a la Common Lisp) would be very
> nice, yes, but is probably an uphill battle.
Why?
> If these are the bits that are exciting in Clojure, then Clojure doesn't
> seem particularly exciting to me. :-)
Couldn't agree more.
J
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-14 16:18 ` Josh
@ 2013-07-14 16:30 ` Juanma Barranquero
2013-07-14 17:14 ` Josh
2013-07-15 7:04 ` Stefan Monnier
1 sibling, 1 reply; 45+ messages in thread
From: Juanma Barranquero @ 2013-07-14 16:30 UTC (permalink / raw)
To: Josh; +Cc: fgallina, emacs-devel
On Sun, Jul 14, 2013 at 6:18 PM, Josh <josh@foxtail.org> wrote:
> (require 'ibuf-macs)
> (ibuffer-awhen (re-search-backward "regex" nil t)
> (list it (match-string-no-properties 0)))
Yes, that's Graham's classic "anaphoric when". when-let seems nicer
because you get to choose the binding name and can easily nest them.
J
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-14 16:30 ` Juanma Barranquero
@ 2013-07-14 17:14 ` Josh
2013-07-14 17:18 ` Juanma Barranquero
0 siblings, 1 reply; 45+ messages in thread
From: Josh @ 2013-07-14 17:14 UTC (permalink / raw)
To: Juanma Barranquero; +Cc: fgallina, emacs-devel
On Sun, Jul 14, 2013 at 9:30 AM, Juanma Barranquero <lekktu@gmail.com> wrote:
> On Sun, Jul 14, 2013 at 6:18 PM, Josh <josh@foxtail.org> wrote:
>
>> (require 'ibuf-macs)
>> (ibuffer-awhen (re-search-backward "regex" nil t)
>> (list it (match-string-no-properties 0)))
>
> Yes, that's Graham's classic "anaphoric when". when-let seems nicer
> because you get to choose the binding name and can easily nest them.
Yes, I agree; I did not intend to suggest that awhen is superior to
when-let, but that canonical versions of such generally useful
functionality should be incorporated into the core where people could
find and use them.
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-14 17:14 ` Josh
@ 2013-07-14 17:18 ` Juanma Barranquero
2013-07-15 6:05 ` Lars Brinkhoff
0 siblings, 1 reply; 45+ messages in thread
From: Juanma Barranquero @ 2013-07-14 17:18 UTC (permalink / raw)
To: Josh; +Cc: fgallina, emacs-devel
On Sun, Jul 14, 2013 at 7:14 PM, Josh <josh@foxtail.org> wrote:
> but that canonical versions of such generally useful
> functionality should be incorporated into the core where people could
> find and use them.
Certainly. aif/awhen/when-let/if-let is so useful that it surely has
been reimplemented a billion times. I have this in my .emacs
(cl-defmacro whereas ((var test) &rest body)
"If TEST is non-nil, bind VAR to it and then run BODY.
Return the value returned by the last form in BODY.
Else, return nil.
\n(fn (VAR TEST) &rest BODY)"
(declare (indent 1) (debug ((sexp form) body)))
`(let ((,var ,test))
(when ,var ,@body)))
(I don't know where the "whereas" name originated, but I know I copied
it from somewhere.)
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-14 2:22 Sweeter Emacs Lisp fgallina
` (2 preceding siblings ...)
2013-07-14 16:18 ` Josh
@ 2013-07-14 17:24 ` Andreas Schwab
2013-07-16 2:13 ` Miles Bader
2013-07-22 15:24 ` Stefan Monnier
5 siblings, 0 replies; 45+ messages in thread
From: Andreas Schwab @ 2013-07-14 17:24 UTC (permalink / raw)
To: fgallina; +Cc: emacs-devel
fgallina@gnu.org writes:
> + make `let` work like `let*`: "let's" stop confusing newcomers.
That will break a lot of code.
Andreas.
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-14 16:27 ` Juanma Barranquero
@ 2013-07-14 19:43 ` Lars Magne Ingebrigtsen
0 siblings, 0 replies; 45+ messages in thread
From: Lars Magne Ingebrigtsen @ 2013-07-14 19:43 UTC (permalink / raw)
To: Juanma Barranquero; +Cc: fgallina, emacs-devel
Juanma Barranquero <lekktu@gmail.com> writes:
>> Destructuring lambda argument lists (a la Common Lisp) would be very
>> nice, yes, but is probably an uphill battle.
>
> Why?
Wouldn't it be difficult to implement it so that it would be
backwards-compatible? Hm... perhaps not?
(defmacro foo ((bar zot &rest gazonk) &body body)
...)
would probably be unambiguous. In which case, I vote for introducing
this in Emacs Lisp. :-)
--
(domestic pets only, the antidote for overdose, milk.)
bloggy blog http://lars.ingebrigtsen.no/
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-14 14:22 ` Lars Magne Ingebrigtsen
2013-07-14 16:27 ` Juanma Barranquero
@ 2013-07-15 3:20 ` Dmitry Gutov
2013-07-15 5:03 ` Stephen J. Turnbull
2013-07-16 2:15 ` Miles Bader
2 siblings, 1 reply; 45+ messages in thread
From: Dmitry Gutov @ 2013-07-15 3:20 UTC (permalink / raw)
To: Lars Magne Ingebrigtsen; +Cc: fgallina, emacs-devel
Lars Magne Ingebrigtsen <larsi@gnus.org> writes:
>> (setq tag (cons "<p>" "</p>"))
>>
>> (defun tag-desc (tag)
>> (concat (upcase (car tag)) "."))
>>
>> (defun tag-desc-stripped (tag)
>> (upcase (replace-regexp-in-string "[<\\/> ]" "" (car tag))))
>>
>> ;; with threading macros
>> (defun tag-desc (tag)
>> (-> (car tag) (upcase) (concat ".")))
>>
>> (defun tag-desc-strip (tag)
>> (->> (car tag) (replace-regexp-in-string "[<\\/> ]" "") (upcase)))
>
> It's not clear what the point of these are. Just to make the code more
> obscure and cool? The new forms (as demonstrated here) even leads to
> longer code, in addition to being pretty opaque. While the "old" code
> is obvious and easy to read.
They're most useful with larger sequences of transformations. You may be
used to reading the code "inside out" by now, but threading operators
are easy to understand, and they make the flow of information much
more obvious.
>> + make `let` work like `let*`: "let's" stop confusing newcomers.
>
> I don't think it's that confusing. It would be more confusing having
> let and let* work differently in Emacs Lisp than in other Lisps, I
> think.
I'd be willing to bet that Emacs Lisp newcomers originating from other
Lisp backgrounds are a distinct minority.
>> + hash-tables: how come that working with hash-tables is such a pain?
>> I love how they are function of themselves in clojure and that
>> there's reader syntax for them.
>>
>> (setq tags (make-hash-table))
>> (puthash tags :p "</p>")
>> (puthash tags :span "</span>")
>> (gethash :span tags) ; -> "</p>"
>
> That's painful? It seems clear and nice to me.
>
>> ;; clojuresque version
>> (setq tags {:p "</p>" :span "</span>"})
>> (:p tags) ; -> "</p>"
>> (tags :p) ; -> "</p>"
>> (:html tags) ; -> nil
>
> This just seems like a "neat" way to write opaque code. Did the Clojure
> people come from a Perl or Scheme background, by any chance?
Most of the adopters come from Java and Ruby, AFAIK. And JavaScript,
especially lately.
But, FYI, the first version of Clojure was written in Common Lisp.
I think the OP is missing the point here, though. While the combination
of Lisp-1 and virtual dispatch looks pretty, it's a non-starter for a
Lisp-2, which Emacs Lisp is.
Clojure's standard library is great even without those, for example take
a look at functions dealing with maps:
http://clojure.org/data_structures#Data Structures-Maps (IPersistentMap)
The API is quite dependent on maps being immutable, though, so it
wouldn't be easy to bring them to Emacs either.
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-15 3:20 ` Dmitry Gutov
@ 2013-07-15 5:03 ` Stephen J. Turnbull
2013-07-16 20:23 ` Dmitry Gutov
0 siblings, 1 reply; 45+ messages in thread
From: Stephen J. Turnbull @ 2013-07-15 5:03 UTC (permalink / raw)
To: Dmitry Gutov; +Cc: fgallina, Lars Magne Ingebrigtsen, emacs-devel
Dmitry Gutov writes:
> >> (defun tag-desc-stripped (tag)
> >> (upcase (replace-regexp-in-string "[<\\/> ]" "" (car tag))))
> >> (defun tag-desc-strip (tag)
> >> (->> (car tag) (replace-regexp-in-string "[<\\/> ]" "") (upcase)))
If you find
(defun tag-desc-stripped (tag)
(upcase (replace-regexp-in-string "[<\\/> ]" "" (car tag))))
hard to read, the conventional grind
(defun tag-desc-stripped (tag)
(upcase (replace-regexp-in-string "[<\\/> ]"
""
(car tag))))
makes things pretty obvious (unless the target reader really can't
read Lisp at all). I don't see a real need based on readability.
And this breaks C-x C-e badly. This isn't just a matter of loss of
convenience; it's a symptom of a major syntax change. It breaks *any*
code analysis tool. And it is unnecessary, except for saving some
keystrokes. You could imagine
(defun threaded-apply-to-1 (arg &rest list-of-fun)
;; actually, just `apply-to' is probably sufficiently mnemonic
(while list-of-fun
(setq arg (funcall (pop list-of-fun) arg)))
arg)
(defun tag-desc-stripped (tag)
(threaded-apply-to-1 tag
#'car
(lambda (x) (replace-regexp-in-string "[<\\/> ]" "" x))
#'upcase))
That style makes me slightly ill, but (1) it's more general than `->'
and `->>' combined, and (2) it doesn't turn malformed function calls
into curried functions implicitly. So it doesn't break C-x C-e and
other tools that depend on the simplicity of Lisp expression syntax.
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-14 17:18 ` Juanma Barranquero
@ 2013-07-15 6:05 ` Lars Brinkhoff
0 siblings, 0 replies; 45+ messages in thread
From: Lars Brinkhoff @ 2013-07-15 6:05 UTC (permalink / raw)
To: emacs-devel
Juanma Barranquero <lekktu@gmail.com> writes:
> Certainly. aif/awhen/when-let/if-let is so useful that it surely has
> been reimplemented a billion times. I have this in my .emacs
>
> (cl-defmacro whereas ((var test) &rest body)
> "If TEST is non-nil, bind VAR to it and then run BODY.
> Return the value returned by the last form in BODY.
> Else, return nil.
> \n(fn (VAR TEST) &rest BODY)"
> (declare (indent 1) (debug ((sexp form) body)))
> `(let ((,var ,test))
> (when ,var ,@body)))
>
> (I don't know where the "whereas" name originated, but I know I copied
> it from somewhere.)
Probably from Erik Naggum:
http://groups.google.com/d/msg/comp.lang.lisp/W_YphmkN_4E/5POxWqpyd7wJ
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-14 16:18 ` Josh
2013-07-14 16:30 ` Juanma Barranquero
@ 2013-07-15 7:04 ` Stefan Monnier
2013-07-15 13:30 ` Bozhidar Batsov
1 sibling, 1 reply; 45+ messages in thread
From: Stefan Monnier @ 2013-07-15 7:04 UTC (permalink / raw)
To: Josh; +Cc: fgallina, emacs-devel
>> ;; clojure.core/if-let
>> ;; ([bindings then] [bindings then else & oldform])
>> ;; Macro
>> ;; bindings => binding-form test
>> ;; If test is true, evaluates then with binding-form bound to the value of
>> ;; test, if not, yields else
We get pretty close with
(pcase TEST
(`nil ELSE)
(BINDING-FORM THEN))
-- Stefan
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-15 7:04 ` Stefan Monnier
@ 2013-07-15 13:30 ` Bozhidar Batsov
2013-07-16 2:26 ` Miles Bader
2013-07-16 9:11 ` Stefan Monnier
0 siblings, 2 replies; 45+ messages in thread
From: Bozhidar Batsov @ 2013-07-15 13:30 UTC (permalink / raw)
To: Stefan Monnier; +Cc: fgallina, Josh, emacs-devel
[-- Attachment #1: Type: text/plain, Size: 907 bytes --]
I'll also feel it's about time the Emacs Lisp standard library got a bit of
facelift. In a time when most Lisp have embraces `first` and `rest`
where're still clinging to functions named `car` and `cdr` for instance.
Sure, lib-cl has `cl-first` and `cl-rest`, but I can't see the harm in
having those aliases in the "standard" lib.
dash.el and s.el show can be used if not directly at least as a source of
inspiration for modernizing a bit the list and string manipulation portions
of the library. We don't even have in built-in equivalents of `filter`,
`select`, etc. I guess most of you have noticed that most non-trivial Emacs
Lisp packages starting with `require 'cl` (or more recently `require
'cl-lib`). This speaks volumes of the limitations that developers are
facing with the current standard lib. We don't need ANSI, a committee or
lots of money to make the library better - so why don't we? :-)
[-- Attachment #2: Type: text/html, Size: 1005 bytes --]
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-14 2:22 Sweeter Emacs Lisp fgallina
` (3 preceding siblings ...)
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-22 15:24 ` Stefan Monnier
5 siblings, 2 replies; 45+ messages in thread
From: Miles Bader @ 2013-07-16 2:13 UTC (permalink / raw)
To: fgallina; +Cc: emacs-devel
fgallina@gnu.org writes:
> + *we need a built-in core mapcan (could be called mapcat), filter and
> sequence concatenation (could be called cat?) function that doesn't
> depends on cl-lib*. This is fundamental stuff isn't it? Why is such a
> need to require a library for it?
Yes, it's completely silly that there's no core mapcan...
[I've been periodically asking for this for I think _decades_ but nobody
seems to care... >< ]
-miles
--
Yossarian was moved very deeply by the absolute simplicity of
this clause of Catch-22 and let out a respectful whistle.
"That's some catch, that Catch-22," he observed.
"It's the best there is," Doc Daneeka agreed.
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-14 14:22 ` Lars Magne Ingebrigtsen
2013-07-14 16:27 ` Juanma Barranquero
2013-07-15 3:20 ` Dmitry Gutov
@ 2013-07-16 2:15 ` Miles Bader
2013-07-16 9:12 ` Stefan Monnier
2 siblings, 1 reply; 45+ messages in thread
From: Miles Bader @ 2013-07-16 2:15 UTC (permalink / raw)
To: Lars Magne Ingebrigtsen; +Cc: fgallina, emacs-devel
Lars Magne Ingebrigtsen <larsi@gnus.org> writes:
>> + *we need a built-in core mapcan (could be called mapcat),
>> filter and sequence concatenation (could be called cat?) function
>> that doesn't depends on cl-lib*. This is fundamental stuff isn't
>> it? Why is such a need to require a library for it?
>
> Why not just use the cl functions?
cl = giant awful ball of hair. Requiring it for somewhing as basic as
mapcan is ... unpleasant.
-miles
--
Dinanzi a me non fuor cose create
se non etterne, e io etterno duro.
Lasciate ogne speranza, voi ch'intrate.
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
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 9:11 ` Stefan Monnier
1 sibling, 1 reply; 45+ messages in thread
From: Miles Bader @ 2013-07-16 2:26 UTC (permalink / raw)
To: Bozhidar Batsov; +Cc: fgallina, Josh, Stefan Monnier, emacs-devel
Bozhidar Batsov <bozhidar@batsov.com> writes:
> I'll also feel it's about time the Emacs Lisp standard library got a
> bit of facelift. In a time when most Lisp have embraces `first` and
> `rest` where're still clinging to functions named `car` and `cdr`
> for instance.
Er, what? I dunno about "weird" lisps like clojure, but AFAICS, car
and cdr are way more used than first and rest... the latter were
half-hearted attempts at making lisp "friendly" but have never seemed
to have gotten much traction; whether they're better is at best,
arguable...
-miles
--
Quotation, n. The act of repeating erroneously the words of another. The words
erroneously repeated.
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-16 2:26 ` Miles Bader
@ 2013-07-16 6:08 ` Thien-Thi Nguyen
2013-07-16 14:07 ` Drew Adams
0 siblings, 1 reply; 45+ messages in thread
From: Thien-Thi Nguyen @ 2013-07-16 6:08 UTC (permalink / raw)
To: Miles Bader; +Cc: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 767 bytes --]
() Miles Bader <miles@gnu.org>
() Tue, 16 Jul 2013 11:26:48 +0900
[...] but AFAICS, car and cdr are way more used than first and
rest... the latter were half-hearted attempts at making lisp
"friendly" but have never seemed to have gotten much traction;
whether they're better is at best, arguable...
CAR and CDR are cool because they align vertically nicely. I spend an
inordinate amount of time choosing sets of identifiers w/ this property.
Then, M-x zone and a drink -- cheap entertainment for the old fool...
--
Thien-Thi Nguyen
GPG key: 4C807502
(if you're human and you know it)
read my lisp: (responsep (questions 'technical)
(not (via 'mailing-list)))
=> nil
[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-16 2:13 ` Miles Bader
@ 2013-07-16 6:14 ` Stephen J. Turnbull
2013-07-16 9:07 ` Stefan Monnier
1 sibling, 0 replies; 45+ messages in thread
From: Stephen J. Turnbull @ 2013-07-16 6:14 UTC (permalink / raw)
To: Miles Bader; +Cc: fgallina, emacs-devel
Miles Bader writes:
> Yes, it's completely silly that there's no core mapcan...
>
> [I've been periodically asking for this for I think _decades_ but nobody
> seems to care... >< ]
"Nobody" is a little extreme:
`mapcan' is a built-in function
-- loaded from "/playpen/src/XEmacs/xemacs/src/sequence.c"
Admittedly it lived in cl-extra.el until 2010/01. So I guess you and
Aidan Kehoe are the only two hackers in the world who care. :-)
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
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
1 sibling, 1 reply; 45+ messages in thread
From: Stefan Monnier @ 2013-07-16 9:07 UTC (permalink / raw)
To: Miles Bader; +Cc: fgallina, emacs-devel
>> + *we need a built-in core mapcan (could be called mapcat), filter and
>> sequence concatenation (could be called cat?) function that doesn't
>> depends on cl-lib*. This is fundamental stuff isn't it? Why is such a
>> need to require a library for it?
> Yes, it's completely silly that there's no core mapcan...
You can (require 'cl-lib) to get it.
It still can't be used in pre-loaded code, but that's the only
restriction,
Stefan
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-15 13:30 ` Bozhidar Batsov
2013-07-16 2:26 ` Miles Bader
@ 2013-07-16 9:11 ` Stefan Monnier
1 sibling, 0 replies; 45+ messages in thread
From: Stefan Monnier @ 2013-07-16 9:11 UTC (permalink / raw)
To: Bozhidar Batsov; +Cc: fgallina, Josh, emacs-devel
> I'll also feel it's about time the Emacs Lisp standard library got a bit of
> facelift. In a time when most Lisp have embraces `first` and `rest`
> where're still clinging to functions named `car` and `cdr` for instance.
> Sure, lib-cl has `cl-first` and `cl-rest`, but I can't see the harm in
> having those aliases in the "standard" lib.
`first' and `rest' are fine when handling lists, but not when using cons
cells which represent other data structures (e.g. pairs, tuples, you
name it).
Of course, using `pcase' you can extract the car and cdr without any
name at all (i.e. using the (FOO . BAR) notation instead).
Stefan
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-16 2:15 ` Miles Bader
@ 2013-07-16 9:12 ` Stefan Monnier
0 siblings, 0 replies; 45+ messages in thread
From: Stefan Monnier @ 2013-07-16 9:12 UTC (permalink / raw)
To: Miles Bader; +Cc: fgallina, Lars Magne Ingebrigtsen, emacs-devel
> cl = giant awful ball of hair. Requiring it for somewhing as basic as
> mapcan is ... unpleasant.
With cl-lib, it's a bit less hairy. Still pretty hairy, admittedly,
but improving.
Stefan
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-16 9:07 ` Stefan Monnier
@ 2013-07-16 11:09 ` Juanma Barranquero
2013-07-16 12:25 ` Andreas Schwab
2013-07-16 20:57 ` Stefan Monnier
0 siblings, 2 replies; 45+ messages in thread
From: Juanma Barranquero @ 2013-07-16 11:09 UTC (permalink / raw)
To: Stefan Monnier; +Cc: fgallina, emacs-devel, Miles Bader
On Tue, Jul 16, 2013 at 11:07 AM, Stefan Monnier
<monnier@iro.umontreal.ca> wrote:
> You can (require 'cl-lib) to get it.
> It still can't be used in pre-loaded code, but that's the only
> restriction,
That's a policy, and not for technical reasons, is it?
The past two weeks, while hacking desktop.el, often I would've loved
to require 'cl-lib to use sequence functions. I didn't, because
desktop.el, though not pre-loaded, it is so commonly used that loading
cl-lib from it would be almost like forcing cl-lib into everybody's
Emacs.
Still, it is a bid sad to be forced to make that kind of decision. cl
contains tons of useful things.
OTOH, cl-lib is currently unconditionally required by 15 files (plus
emacs-lisp/cl*.el):
doc-view.el
edmacro.el
image-dired.el
profiler.el
shadowfile.el
thumbs.el
wid-edit.el
calendar\todo-mode.el
emacs-lisp\edebug.el
emacs-lisp\ert.el
eshell\em-ls.el
eshell\em-term.el
progmodes\ebrowse.el
progmodes\gdb-mi.el
progmodes\sql.el
so it's a growing trend...
Juanma
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
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 20:57 ` Stefan Monnier
1 sibling, 2 replies; 45+ messages in thread
From: Andreas Schwab @ 2013-07-16 12:25 UTC (permalink / raw)
To: Juanma Barranquero; +Cc: fgallina, Miles Bader, Stefan Monnier, emacs-devel
Juanma Barranquero <lekktu@gmail.com> writes:
> The past two weeks, while hacking desktop.el, often I would've loved
> to require 'cl-lib to use sequence functions. I didn't, because
> desktop.el, though not pre-loaded, it is so commonly used that loading
> cl-lib from it would be almost like forcing cl-lib into everybody's
> Emacs.
There is nothing wrong with using the macros from cl-lib.
> OTOH, cl-lib is currently unconditionally required by 15 files (plus
> emacs-lisp/cl*.el):
Only when compiling.
Andreas.
--
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE 1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-16 12:25 ` Andreas Schwab
@ 2013-07-16 13:04 ` Thierry Volpiatto
2013-07-16 13:42 ` Juanma Barranquero
1 sibling, 0 replies; 45+ messages in thread
From: Thierry Volpiatto @ 2013-07-16 13:04 UTC (permalink / raw)
To: emacs-devel
Andreas Schwab <schwab@suse.de> writes:
> Juanma Barranquero <lekktu@gmail.com> writes:
>
>> The past two weeks, while hacking desktop.el, often I would've loved
>> to require 'cl-lib to use sequence functions. I didn't, because
>> desktop.el, though not pre-loaded, it is so commonly used that loading
>> cl-lib from it would be almost like forcing cl-lib into everybody's
>> Emacs.
>
> There is nothing wrong with using the macros from cl-lib.
There is nothing wrong using the functions from cl-lib too AFAIK.
(Like everybody does)
>> OTOH, cl-lib is currently unconditionally required by 15 files (plus
>> emacs-lisp/cl*.el):
>
> Only when compiling.
No 19 files are requiring cl-lib at runtime actually.
--
Thierry
Get my Gnupg key:
gpg --keyserver pgp.mit.edu --recv-keys 59F29997
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
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
1 sibling, 1 reply; 45+ messages in thread
From: Juanma Barranquero @ 2013-07-16 13:42 UTC (permalink / raw)
To: Andreas Schwab; +Cc: fgallina, Miles Bader, Stefan Monnier, emacs-devel
On Tue, Jul 16, 2013 at 2:25 PM, Andreas Schwab <schwab@suse.de> wrote:
> There is nothing wrong with using the macros from cl-lib.
I wasn't talking about the macros, but the sequence functions from
cl-seq. They are one of the most useful parts of cl-lib.
> Only when compiling.
No. These 15 files, plus emacs-lisp/cl-*.el, do require cl-lib at
runtime. There are > 100 packages that require cl-lib when compiling.
Juanma
^ permalink raw reply [flat|nested] 45+ messages in thread
* RE: Sweeter Emacs Lisp
2013-07-16 6:08 ` Thien-Thi Nguyen
@ 2013-07-16 14:07 ` Drew Adams
0 siblings, 0 replies; 45+ messages in thread
From: Drew Adams @ 2013-07-16 14:07 UTC (permalink / raw)
To: Thien-Thi Nguyen, Miles Bader; +Cc: emacs-devel
> [...] but AFAICS, car and cdr are way more used than first and
> rest... the latter were half-hearted attempts at making lisp
> "friendly" but have never seemed to have gotten much traction;
> whether they're better is at best, arguable...
>
> CAR and CDR are cool because they align vertically nicely.
Not to mention the coolness of cadr, cdar, caar, cddr, and all the
rest (Common Lisp, at least). Their names tell you what they do,
no matter how complex the operation (e.g. cdaadr).
That's not a reason not to define meaningfully named access macros
for particular contexts. And it's not a reason not to allow `first'
etc. macros or `nth', `elt', `aref' etc. functions.
It's just to point out a very useful naming pattern that, once one
gets used to it, is beyond compare.
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-16 13:42 ` Juanma Barranquero
@ 2013-07-16 14:38 ` Andreas Schwab
2013-07-16 14:42 ` Juanma Barranquero
0 siblings, 1 reply; 45+ messages in thread
From: Andreas Schwab @ 2013-07-16 14:38 UTC (permalink / raw)
To: Juanma Barranquero; +Cc: fgallina, Miles Bader, Stefan Monnier, emacs-devel
Juanma Barranquero <lekktu@gmail.com> writes:
> No. These 15 files, plus emacs-lisp/cl-*.el, do require cl-lib at
> runtime.
???
lisp/doc-view.el:(eval-when-compile (require 'cl-lib))
Andreas.
--
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE 1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-16 14:38 ` Andreas Schwab
@ 2013-07-16 14:42 ` Juanma Barranquero
0 siblings, 0 replies; 45+ messages in thread
From: Juanma Barranquero @ 2013-07-16 14:42 UTC (permalink / raw)
To: Andreas Schwab; +Cc: fgallina, Miles Bader, Stefan Monnier, emacs-devel
On Tue, Jul 16, 2013 at 4:38 PM, Andreas Schwab <schwab@suse.de> wrote:
> lisp/doc-view.el:(eval-when-compile (require 'cl-lib))
You're looking at an old doc-view.el, before this change:
2013-07-12 Glenn Morris <rgm@gnu.org>
* doc-view.el: Require cl-lib at runtime too.
(doc-view-remove-if): Remove.
(doc-view-search-next-match, doc-view-search-previous-match):
Use cl-remove-if.
Juanma
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-15 5:03 ` Stephen J. Turnbull
@ 2013-07-16 20:23 ` Dmitry Gutov
2013-07-17 14:04 ` Lars Magne Ingebrigtsen
0 siblings, 1 reply; 45+ messages in thread
From: Dmitry Gutov @ 2013-07-16 20:23 UTC (permalink / raw)
To: Stephen J. Turnbull; +Cc: fgallina, Lars Magne Ingebrigtsen, emacs-devel
On 15.07.2013 9:03, Stephen J. Turnbull wrote:
> If you find
>
> (defun tag-desc-stripped (tag)
> (upcase (replace-regexp-in-string "[<\\/> ]" "" (car tag))))
>
> hard to read,
This is still a trivial example. And no, now I don't, having spent a
couple of years or so writing Elisp. But I still remember that reading
functions "from inside out" was one of the harder parts, especially with
the level of nesting that one can often observe in core Emacs packages.
Look, for example, at `calculate-lisp-indent'.
Here are some appreciative opinions with better examples:
http://blog.8thlight.com/colin-jones/2011/03/27/clojure-mad-science-an-evil-threading-macro-experiment.html
http://debasishg.blogspot.ru/2010/04/thrush-in-clojure.html
http://thecomputersarewinning.com/post/Clojure-Thrush-Operator/
> And this breaks C-x C-e badly.
No more than using local variables, I'd say. Except when you're using
something like `edebug' in dynamic scoping mode (with lexical scoping,
`edebug' doesn't see local vars yet).
> This isn't just a matter of loss of
> convenience; it's a symptom of a major syntax change. It breaks *any*
> code analysis tool.
I don't see how. The analysis tools have to expand macros anyway, or
they would stumble and break when encountering any macro not from a
predefined set.
> And it is unnecessary, except for saving some
> keystrokes. You could imagine
>
> (defun threaded-apply-to-1 (arg &rest list-of-fun)
> ;; actually, just `apply-to' is probably sufficiently mnemonic
> (while list-of-fun
> (setq arg (funcall (pop list-of-fun) arg)))
> arg)
>
> (defun tag-desc-stripped (tag)
> (threaded-apply-to-1 tag
> #'car
> (lambda (x) (replace-regexp-in-string "[<\\/> ]" "" x))
> #'upcase))
>
> That style makes me slightly ill, but (1) it's more general than `->'
> and `->>' combined, and (2) it doesn't turn malformed function calls
> into curried functions implicitly. So it doesn't break C-x C-e and
> other tools that depend on the simplicity of Lisp expression syntax.
True, that's also an option. Here's an implementation in Clojure[0]:
(defn thrush [a & args]
((apply comp (reverse args)) a))
Incidentally, Clojure has a shorter reader macro for anonymous
functions. Yours would look like this:
#(replace-regexp-in-string "[<\\/> ]" "" %)
And being a Lisp-1, it doesn't need the hash-quotes before the other
arguments.
[0] http://blog.fogus.me/2010/09/28/thrush-in-clojure-redux/
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-16 11:09 ` Juanma Barranquero
2013-07-16 12:25 ` Andreas Schwab
@ 2013-07-16 20:57 ` Stefan Monnier
1 sibling, 0 replies; 45+ messages in thread
From: Stefan Monnier @ 2013-07-16 20:57 UTC (permalink / raw)
To: Juanma Barranquero; +Cc: fgallina, emacs-devel, Miles Bader
>> You can (require 'cl-lib) to get it. It still can't be used in
>> pre-loaded code, but that's the only restriction,
> That's a policy, and not for technical reasons, is it?
Mostly policy, indeed. Using it in "early pre-loaded code" has some
technical problems related to bootstrapping, but other than that I think
we could preload cl-lib without too much trouble, but policy-wise I'd
rather not to do (at least not for now).
> The past two weeks, while hacking desktop.el, often I would've loved
> to require 'cl-lib to use sequence functions. I didn't, because
> desktop.el, though not pre-loaded, it is so commonly used that loading
> cl-lib from it would be almost like forcing cl-lib into everybody's
> Emacs.
Feel free to (require 'cl-lib) for desktop.el since desktop.el is
not preloaded. The whole point of the big "cl-" rename and the partial
rewrite of some parts of CL's code for cl-lib was specifically so that
most packages can use cl-lib's functions rather than tip-toe around
the mapcan.
Stefan
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-16 20:23 ` Dmitry Gutov
@ 2013-07-17 14:04 ` Lars Magne Ingebrigtsen
2013-07-17 15:07 ` Dmitry Gutov
0 siblings, 1 reply; 45+ messages in thread
From: Lars Magne Ingebrigtsen @ 2013-07-17 14:04 UTC (permalink / raw)
To: Dmitry Gutov; +Cc: fgallina, Stephen J. Turnbull, emacs-devel
Dmitry Gutov <dgutov@yandex.ru> writes:
>> (defun tag-desc-stripped (tag)
>> (upcase (replace-regexp-in-string "[<\\/> ]" "" (car tag))))
>>
>> hard to read,
>
> This is still a trivial example. And no, now I don't, having spent a
> couple of years or so writing Elisp. But I still remember that reading
> functions "from inside out" was one of the harder parts,
I've never understood what people mean by "reading from the inside out".
In C, that statement would have been
upcase(replace_regexp_in_string("[<\\/> ]", "", car(tag)));
Of course, if you've only programmed dotted languages like Java, you may
have a problem. (That goes without saying in any context, though.)
> especially with the level of nesting that one can often observe in
> core Emacs packages.
There's a cultural element, though. C people have a tendency to assign
values to variables more, so you get a more imperative style.
(Especially since you have to do a lot of manual memory management
stuff, often.)
> Here are some appreciative opinions with better examples:
>
> http://blog.8thlight.com/colin-jones/2011/03/27/clojure-mad-science-an-evil-threading-macro-experiment.html
Yeah. that's pretty much incomprehensible and confirms my prejudices
against the taste level of the Clojure people. Are you sure they
haven't managed to squeeze monads into the language, too? For extra
academic brownie points?
> Incidentally, Clojure has a shorter reader macro for anonymous
> functions. Yours would look like this:
>
> #(replace-regexp-in-string "[<\\/> ]" "" %)
*barf*
I love how Emacs Lisp (and Common Lisp) eschew all these syntactical
tricks. They have dead simple syntaxes, and makes reading code clear
and easy. You get constructs that are unambiguous and general, even
though they're somewhat longer than Perly stuff like the above.
--
(domestic pets only, the antidote for overdose, milk.)
bloggy blog http://lars.ingebrigtsen.no/
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-17 14:04 ` Lars Magne Ingebrigtsen
@ 2013-07-17 15:07 ` Dmitry Gutov
0 siblings, 0 replies; 45+ messages in thread
From: Dmitry Gutov @ 2013-07-17 15:07 UTC (permalink / raw)
To: Lars Magne Ingebrigtsen; +Cc: fgallina, Stephen J. Turnbull, emacs-devel
Lars Magne Ingebrigtsen <larsi@gnus.org> writes:
> I've never understood what people mean by "reading from the inside out".
> In C, that statement would have been
>
> upcase(replace_regexp_in_string("[<\\/> ]", "", car(tag)));
>
> Of course, if you've only programmed dotted languages like Java, you may
> have a problem. (That goes without saying in any context, though.)
You know, Java also has method calls with implicit receiver (self).
> There's a cultural element, though. C people have a tendency to assign
> values to variables more, so you get a more imperative style.
If a variable is assigned only once, it's not necessarily imperative
style. But yes, this is the tendency, and in this case, to follow the
control flow you can read the code from top to bottom, and the nested
calls, while common, are usually relatively simple.
> Yeah. that's pretty much incomprehensible and confirms my prejudices
> against the taste level of the Clojure people. Are you sure they
> haven't managed to squeeze monads into the language, too? For extra
> academic brownie points?
Only in contrib:
http://richhickey.github.io/clojure-contrib/monads-api.html
> I love how Emacs Lisp (and Common Lisp) eschew all these syntactical
> tricks. They have dead simple syntaxes, and makes reading code clear
> and easy. You get constructs that are unambiguous and general, even
> though they're somewhat longer than Perly stuff like the above.
I find that code rather readable and extensible enough (even when you
come back to it a few weeks later), and these would be the common
criticisms of Perl.
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-14 2:22 Sweeter Emacs Lisp fgallina
` (4 preceding siblings ...)
2013-07-16 2:13 ` Miles Bader
@ 2013-07-22 15:24 ` Stefan Monnier
2013-07-22 16:33 ` Thien-Thi Nguyen
5 siblings, 1 reply; 45+ messages in thread
From: Stefan Monnier @ 2013-07-22 15:24 UTC (permalink / raw)
To: fgallina; +Cc: emacs-devel
> + The *threading* macros "->" and "->>":
Feel free to contribute such macros. I probably wouldn't want to call
them "->" and "->>". The name should probably include "thread" or
"pipe". To make them useful, they should come with good edebug
support, which may turn out to be the more tricky part.
> + when-let, if-let:
As mentioned, `pcase' comes pretty close to `if-let', so I don't feel
a strong need for it. OTOH for when-let you'd need something like
(pcase <test>
(`(and (pred identity) ,<binding-form>) <body>))
which is uglier. So maybe a when-let makes sense, tho I'd prefer a when-let*
(which has also been seen under the name let-and, IIRC).
> + *we need a built-in core mapcan (could be called mapcat), filter and
> sequence concatenation (could be called cat?) function that doesn't
> depends on cl-lib*. This is fundamental stuff isn't it? Why is such a
> need to require a library for it?
The whole point of the big rename and partial rewrite of CL into cl-lib
was so that these functions can be used anywhere, thus making it
unnecessary to duplicate them into "core" Elisp.
> + Destructuring in defun and let: This looks weirder than I thought
> because of our (ab)use of parens everywhere, but I feel this is
> something brillant to have as part of the core language.
For destructuring let we have pcase-let. I have some tentative
pcase-lambda but haven't come up with something good enough yet.
I'm definitely open to suggestions here. As for including it directly
into "core" `defun', and `let', there are some technical issues (mostly
linked to bootstrapping and the performance cost especially in
interpreted code), but I do want to make pcase patterns more generally
available (e.g. making dolist work like pcase-dolist).
Stefan
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-22 15:24 ` Stefan Monnier
@ 2013-07-22 16:33 ` Thien-Thi Nguyen
2013-07-22 21:04 ` Stefan Monnier
0 siblings, 1 reply; 45+ messages in thread
From: Thien-Thi Nguyen @ 2013-07-22 16:33 UTC (permalink / raw)
To: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1005 bytes --]
() Stefan Monnier <monnier@iro.umontreal.ca>
() Mon, 22 Jul 2013 11:24:13 -0400
So maybe a when-let makes sense, tho I'd prefer a when-let*
(which has also been seen under the name let-and, IIRC).
Are you willing to consider Scheme's ‘and-let*’ (SRFI 2).
IIRC i also proposed, maybe a year back, a Schemish ‘cond’
(with ‘=>’) but it was rejected. RMS suggested instead:
(cond VAR (CONDITION [BODY...])
...)
which would bind VAR to the (non-nil) value of CONDITION
such that BODY can refer to it, equivalent to:
(let (VAR)
(cond ((setq VAR CONDITION) [BODY...])
...))
I like this; it strikes me as more Lispy. Unfortunately, i don't
remember if this "cond w/ VAR" went anywhere (so probably it didn't).
--
Thien-Thi Nguyen
GPG key: 4C807502
(if you're human and you know it)
read my lisp: (responsep (questions 'technical)
(not (via 'mailing-list)))
=> nil
[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-22 16:33 ` Thien-Thi Nguyen
@ 2013-07-22 21:04 ` Stefan Monnier
2013-07-23 4:37 ` Thien-Thi Nguyen
0 siblings, 1 reply; 45+ messages in thread
From: Stefan Monnier @ 2013-07-22 21:04 UTC (permalink / raw)
To: Thien-Thi Nguyen; +Cc: emacs-devel
> So maybe a when-let makes sense, tho I'd prefer a when-let*
> (which has also been seen under the name let-and, IIRC).
> Are you willing to consider Scheme's ‘and-let*’ (SRFI 2).
Sounds like the same thing, yes.
> IIRC i also proposed, maybe a year back, a Schemish ‘cond’
> (with ‘=>’) but it was rejected. 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>))
-- Stefan
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
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
0 siblings, 2 replies; 45+ messages in thread
From: Thien-Thi Nguyen @ 2013-07-23 4:37 UTC (permalink / raw)
To: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1905 bytes --]
() 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>))
Yes, i see this can be used as the basis of the other forms. Cool.
Has anyone done a C implementation? Here's a sketch (in *scratch*):
(defmacro cool-cond (&rest clauses)
(let ((rev (reverse clauses))
one elab)
(while (setq one (pop rev))
(setq elab (pcase one
(`(let ,var ,exp)
`((t (let ((,var ,exp))
(cond ,@elab)))))
(`(let ,var)
`((t (let (,var)
(cond ,@elab)))))
(_ (cons one elab)))))
`(cond ,@elab)))
(macroexpand '(cool-cond
(nil t)
(t nil)))
(cond
(nil t)
(t nil))
(macroexpand '(cool-cond
(let bar 'none)
(nil t)
(let foo (list bar 42))
(foo)
(t nil)))
(cond
(t
(let
((bar 'none))
(cond
(nil t)
(t
(let
((foo
(list bar 42)))
(cond
(foo)
(t nil))))))))
--
Thien-Thi Nguyen
GPG key: 4C807502
(if you're human and you know it)
read my lisp: (responsep (questions 'technical)
(not (via 'mailing-list)))
=> nil
[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-23 4:37 ` Thien-Thi Nguyen
@ 2013-08-10 2:52 ` Stefan Monnier
2013-08-10 10:08 ` Pascal J. Bourguignon
1 sibling, 0 replies; 45+ messages in thread
From: Stefan Monnier @ 2013-08-10 2:52 UTC (permalink / raw)
To: emacs-devel
> (defmacro cool-cond (&rest clauses)
> (let ((rev (reverse clauses))
> one elab)
> (while (setq one (pop rev))
> (setq elab (pcase one
> (`(let ,var ,exp)
> `((t (let ((,var ,exp))
> (cond ,@elab)))))
> (`(let ,var)
> `((t (let (,var)
> (cond ,@elab)))))
> (_ (cons one elab)))))
> `(cond ,@elab)))
That sounds about right. Two remaining problems:
- Easy one: improve the macro to reduce the nesting depth (consecutive
`let's should be turned into a single let*, and consecutive non-lets
should be together in a single `cond'). You can probably use
macroexp-let* and macroexp-if for that.
- Hard one: come up with a better name.
Stefan
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: Sweeter Emacs Lisp
2013-07-23 4:37 ` Thien-Thi Nguyen
2013-08-10 2:52 ` Stefan Monnier
@ 2013-08-10 10:08 ` Pascal J. Bourguignon
2013-08-10 16:27 ` Drew Adams
1 sibling, 1 reply; 45+ messages in thread
From: Pascal J. Bourguignon @ 2013-08-10 10:08 UTC (permalink / raw)
To: emacs-devel
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
^ permalink raw reply [flat|nested] 45+ messages in thread
* RE: Sweeter Emacs Lisp
2013-08-10 10:08 ` Pascal J. Bourguignon
@ 2013-08-10 16:27 ` Drew Adams
0 siblings, 0 replies; 45+ messages in thread
From: Drew Adams @ 2013-08-10 16:27 UTC (permalink / raw)
To: Pascal J. Bourguignon, emacs-devel
> > > 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.
+1
> In this aspect, RMS' suggestion is better.
It's better, but it too is not a great idea, IMO. Clearest of
all is what y'all *started* with - plain ol' lisp:
(let (x)
(cond ((...x...)
...)
((progn (setq x ...) ...)
...)))
or more likely:
(cond ((let ((x ...))...)
...)
((let ((x ...))...)
...))
or typically clearer, when possible (e.g., subforms refer to the
variable explicitly or do not evaluate code that refers to it):
(cond ((let ((x1 ...))...)
...)
((let ((x2 ...))...)
...)
depending on the need/context.
> 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))
>
> --> (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))
Quelle horreur ! The second (the macroexpansion of the first) is
more readable than the first.
And the second is but a mechanical expansion. A human would write
something simpler, e.g. (and (< x z) 4) instead of (cond ((< x z) 4)).
And with average-length function and variable names the second form
is not much more verbose than the first. Saving a few parens and
explicit conditionals at the expense of clarity wrt scope etc. is
usually an unwise trade-off.
YAGNI.
^ permalink raw reply [flat|nested] 45+ messages in thread
end of thread, other threads:[~2013-08-10 16:27 UTC | newest]
Thread overview: 45+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
2013-08-10 16:27 ` Drew Adams
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).