Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what's the use for paredit-convolute-sexp in paredit mode

Tags:

elisp

paredit

It changes

(a b c d (1 2 |3 4) ha ha ha)

into

|(1 2 (a b c d 3 4 ha ha ha))

What is the use for that transformation?

like image 431
Jisang Yoo Avatar asked Aug 12 '13 16:08

Jisang Yoo


4 Answers

Most examples have shown narrowing scope, but I expect you'd most likely use this if you realized you had a let form inside an if and realized you needed those bindings in the other branch of the if form as well.

Let's say you're a troll and you've found a delicious-looking thief.

(defn eat-hobbit [hobbit]
  (if (is-cooked? hobbit)
    (eat! hobbit)
    (let [is-fat (< too-greasy (:fat-content hobbit))]
      (if is-fat
        (eat! (deep-fry hobbit))
        (eat! (saute hobbit))))))

You realize you should probably be making better health choices and not just eat every hobbit you come across, cooked or not, so you decide to decide whether or not to eat the hobbit in the first place based on how fatty it is. You need to know is-fat before you decide to eat! So, you want to elevate that let. Put the cursor after the binding vector in (let [is-fat ...] and M-? (and clean up whitespace with M-j M-q):

(defn eat-hobbit [hobbit]
  (let [is-fat (< too-greasy (:fat-content hobbit))]
    (if (is-cooked? hobbit)
      (eat! hobbit)
      (if is-fat
        (eat! (deep-fry hobbit))
        (eat! (saute hobbit))))))

You're not DONE making better food choices yet, but now the binding is in the right scope to make better decisions.

Let's try it again. We should really ask if the hobbit is fat first, so put the cursor after (if is-fat and M-? (and cleanup with M-j M-q again):

(defn eat-hobbit [hobbit]
  (let [is-fat (< too-greasy (:fat-content hobbit))]
    (if is-fat
      (if (is-cooked? hobbit)
        (eat! hobbit)

        (eat! (deep-fry hobbit))
        (eat! (saute hobbit))))))

Hmm. That's not quite VALID yet—there's an extra form in the if—but it's very close to where we want to be. At this point, we can easily use the more common bindings of paredit to barf, transpose, and/or kill the extra form in the if, depending on how sincere we are in our intentions towards healthy eating. We could also splice the two if forms together for brevity.

like image 60
John Christopher Jones Avatar answered Oct 25 '22 13:10

John Christopher Jones


Also just a quick add regarding practical use, you may like to check the minute 1:40 of this tutorial: http://emacsrocks.com/e14.html

calling M-? with the cursor on the opening of do-something broadens the scope of the let, from this:

(defun my-other-command ()
  (when (and (this-predicate)
             (that-predicate))
    (let ((v (calculate-v))
          (x (calculate-x)))
      (do-something)
      (do-some-more)
      (do-a-third-thing))))

directly to this:

(defun my-other-command ()
  (let ((v (calculate-v))
        (x (calculate-x)))
    (when (and (this-predicate)
               (that-predicate))
      (do-something)
      (do-some-more)
      (do-a-third-thing))))

cheers! Andres

like image 17
fr_andres Avatar answered Oct 25 '22 14:10

fr_andres


Strictly speaking, it's used for reversing the nesting of an inner expression.

As an example:

(let [foo bar] (if a b| c))

becomes

(if a b (let [foo bar]| c))

As for use case, I've never had a practical use for it specifically, but it's a nice building block for a larger macro

like image 7
SheetJS Avatar answered Oct 25 '22 13:10

SheetJS


To add to Nirk's answer

For smartparens users, M-x sp-prefix-save-excursion M-x sp-convolute-sexp changes

(let [foo bar] (if a b| c))

and

(let [foo bar] (if a b |c))

into

(if a b (let [foo bar] |c))

For paredit users, M-x paredit-convolute-sexp changes

(let [foo bar] (if a b| c))

and

(let [foo bar] (if a b |c))

into

|(if a b(let [foo bar]  c))

and

|(if a b (let [foo bar] c))

For those who uses neither, you can still use the convolute commands if you include

(require 'paredit)
(require 'smartparens)

in the init file and those two lines alone do NOT set up your Emacs to use paredit mode or smartparens mode and so all is well. If you install the paredit package from a package archive, the autoloads file may or may not set up Emacs to use paredit mode, and paredit has no Customize interface. If you install smartparens package, whatever the autoloads file does, you can use Customize interface to set smartparens-global-mode to nil, if its default is not nil (default is nil though for now).

like image 3
Jisang Yoo Avatar answered Oct 25 '22 15:10

Jisang Yoo