all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* Can el-search-query-replace replace mapcar with --map ?
@ 2017-12-22 11:45 Chunyang Xu
  2017-12-22 17:17 ` Michael Heerdegen
  0 siblings, 1 reply; 4+ messages in thread
From: Chunyang Xu @ 2017-12-22 11:45 UTC (permalink / raw)
  To: help-gnu-emacs; +Cc: michael_heerdegen

Hi.

'C-h P el-search' mentions 'el-search-query-replace' can replace 'mapc'
with 'dolist'. I would like to know if it is also possible to replace
'mapcar' with '--map' (from dash.el), for example, change

  (mapcar (lambda (x) (* x x)) '(1 2 3))

into

  (--map (* it it) '(1 2 3))

I have tried:

   M-x el-search-query-replace RET
   `(mapcar (lambda (,val) . ,body) ,list) -> `(--map ,@body ,list) RET

It gives me:

  (--map
   (* x x)
   '(1 2 3))

it is almost right except the variable name, '--map' only knows 'it',
not 'x'.

Any suggestion?

Thanks.



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Can el-search-query-replace replace mapcar with --map ?
  2017-12-22 11:45 Can el-search-query-replace replace mapcar with --map ? Chunyang Xu
@ 2017-12-22 17:17 ` Michael Heerdegen
  2017-12-23  6:17   ` Chunyang Xu
  0 siblings, 1 reply; 4+ messages in thread
From: Michael Heerdegen @ 2017-12-22 17:17 UTC (permalink / raw)
  To: Chunyang Xu; +Cc: help-gnu-emacs

Chunyang Xu <mail@xuchunyang.me> writes:

> It gives me:
>
>   (--map
>    (* x x)
>    '(1 2 3))

which is expected, of course.

The transformation you want is not trivial, and there are some
problematic cases when it gets complicated - e.g. when the mapped lambda
uses in its body a local variable with the same name as the argument
variable, like in
  
#+begin_src emacs-lisp
  (lambda (x) (let ((x (1+ x))) (* x x)))
#+end_src

But that should be corner cases in practice.

I would define a helper function to perform the renaming of the lambda
argument into "it" - something like

#+begin_src emacs-lisp
(defun transform-lambda-form-for---map (lambda-form)
  (pcase-let ((`(lambda (,var) . ,body) lambda-form))
    (macroexpand-1
     `(cl-symbol-macrolet ((,var it))
        ,@body))))
#+end_src

and then el-search-query-replace with the rule

#+begin_src emacs-lisp
`(mapcar ,lambda-form ,list)
 ->
`(--map ,(transform-lambda-form-for---map lambda-form) ,list)
#+end_src

Does that work ok for you?


Regards,

Michael.



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Can el-search-query-replace replace mapcar with --map ?
  2017-12-22 17:17 ` Michael Heerdegen
@ 2017-12-23  6:17   ` Chunyang Xu
  2017-12-23 14:03     ` Michael Heerdegen
  0 siblings, 1 reply; 4+ messages in thread
From: Chunyang Xu @ 2017-12-23  6:17 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: help-gnu-emacs


Michael Heerdegen writes:

> Chunyang Xu <mail@xuchunyang.me> writes:
>
>> It gives me:
>>
>>   (--map
>>    (* x x)
>>    '(1 2 3))
>
> which is expected, of course.
>
> The transformation you want is not trivial, and there are some
> problematic cases when it gets complicated - e.g. when the mapped lambda
> uses in its body a local variable with the same name as the argument
> variable, like in
>
> #+begin_src emacs-lisp
>   (lambda (x) (let ((x (1+ x))) (* x x)))
> #+end_src
>
> But that should be corner cases in practice.
>
> I would define a helper function to perform the renaming of the lambda
> argument into "it" - something like
>
> #+begin_src emacs-lisp
> (defun transform-lambda-form-for---map (lambda-form)
>   (pcase-let ((`(lambda (,var) . ,body) lambda-form))
>     (macroexpand-1
>      `(cl-symbol-macrolet ((,var it))
>         ,@body))))
> #+end_src
>
> and then el-search-query-replace with the rule
>
> #+begin_src emacs-lisp
> `(mapcar ,lambda-form ,list)
>  ->
> `(--map ,(transform-lambda-form-for---map lambda-form) ,list)
> #+end_src
>
> Does that work ok for you?

It works fine for my example:

  (mapcar (lambda (x) (* x x)) '(1 2 3))

but not

  (mapcar (lambda (x) (let ((x (1+ x))) (* x x))) '(1 2 3))

with the exact same patterns, 'el-search-query-replace' reports

  el-search--format-replacement: Error in ‘el-search--format-replacement’ - please make a bug report

I guess this is excepted by you, even though
'transform-lambda-form-for---map' is correct for both cases:

  (transform-lambda-form-for---map
   (lambda (x) (* x x)))
       => (* it it)

  (transform-lambda-form-for---map
   (lambda (x) (let ((x (1+ x))) (* x x))))
       => (let ((x (1+ it))) (* x x))


By the way, is there a way to tidy the code after
'el-search-query-replace' ? For the same example above, it produces

  (--map
   (* it it)
   '(1 2 3))

but I want

  (--map (* it it) '(1 2 3))

right now I have to do it manually via M-^ ('delete-indentation'), which
is not very convenient.


Thanks for your help.



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Can el-search-query-replace replace mapcar with --map ?
  2017-12-23  6:17   ` Chunyang Xu
@ 2017-12-23 14:03     ` Michael Heerdegen
  0 siblings, 0 replies; 4+ messages in thread
From: Michael Heerdegen @ 2017-12-23 14:03 UTC (permalink / raw)
  To: Chunyang Xu; +Cc: help-gnu-emacs

Chunyang Xu <mail@xuchunyang.me> writes:

> It works fine for my example:
>
>   (mapcar (lambda (x) (* x x)) '(1 2 3))
>
> but not
>
>   (mapcar (lambda (x) (let ((x (1+ x))) (* x x))) '(1 2 3))
>
> with the exact same patterns, 'el-search-query-replace' reports
>
>   el-search--format-replacement: Error in
>   ‘el-search--format-replacement’ - please make a bug report
>
> I guess this is excepted by you, even though
> 'transform-lambda-form-for---map' is correct for both cases:
>
>   (transform-lambda-form-for---map
>    (lambda (x) (* x x)))
>        => (* it it)
>
>   (transform-lambda-form-for---map
>    (lambda (x) (let ((x (1+ x))) (* x x))))
>        => (let ((x (1+ it))) (* x x))

It's not that simple.  If you bind print-circle and print-gensym to t,
you see that `symbol-macrolet' renames the let-bound variable x to an
uninterned symbol:

#+begin_src emacs-lisp
(transform-lambda-form-for---map '(lambda (x) (let ((x (1+ x))) (* x x))))
==>
(let
    ((#1=#:x
      (1+ it)))
  (* #1# #1#))
#+end_src

The current version of el-search doesn't yet allow uninterned symbols in
the replacement.  The result is not what you want in your case anyway.
As I said - making every case work correctly would need something more
complicated than what I had suggested.

> By the way, is there a way to tidy the code after
> 'el-search-query-replace' ? For the same example above, it produces
>
>   (--map
>    (* it it)
>    '(1 2 3))
>
> but I want
>
>   (--map (* it it) '(1 2 3))
>
> right now I have to do it manually via M-^ ('delete-indentation'), which
> is not very convenient.

I know about that problem, but currently, you must do it manually.
el-search currently use "pp.el" to format the replacement.  It is not
very sophisticated, I want to replace it with something better in the
future.  Nobody has written a nicer printer yet.  Printing an expression
that is lisp code in a way that is appealing to humans is a challenge of
its own.


Regards,

Michael.



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2017-12-23 14:03 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-12-22 11:45 Can el-search-query-replace replace mapcar with --map ? Chunyang Xu
2017-12-22 17:17 ` Michael Heerdegen
2017-12-23  6:17   ` Chunyang Xu
2017-12-23 14:03     ` Michael Heerdegen

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.