Как отформатировать вложенные множественные-привязки пустым способом? - PullRequest
4 голосов
/ 01 февраля 2020

В последнее время я часто вкладываю несколько функций, которые возвращают несколько значений. Однако, в отличие от let, который позволяет мне элегантно записать эти вызовы в одно большое утверждение, я всегда получаю много отступов.

Мой вопрос : наличие нескольких многократных Значимые функции, такие как

(defun return-1-and-2 ()
  (values 1 2))

(defun return-3-and-4 ()
  (values 3 4))

, можно ли достичь того же, что и

(multiple-value-bind (one two)
    (return-1-and-2)
  (multiple-value-bind (three four)
      (return-3-and-4)
    (list one two three four)))

, но записать это более кратко let, т. е. что-то вроде

(multiple-let (((one two) (return-1-and-2))
               ((three four) (return-3-and-4)))
  (list one two three four))

?

Ответы [ 3 ]

5 голосов
/ 01 февраля 2020

Возможно, в библиотеках есть похожие конструкции.

Обратите внимание, что это больше похоже на let*, а не let, поскольку область видимости вложена.

Можно написать макрос. Например:

(defmacro multiple-value-let* ((&rest bindings) &body body)

  "Sets the scope for several ((var-0 ... var-n) form)
  binding clauses, using the multiple return values of the form."

  (if (null bindings)
      `(progn ,@body)
    (destructuring-bind (((&rest vars) form) &rest rest-bindings)
        bindings
      `(multiple-value-bind ,vars
           ,form
         (multiple-value-let* ,rest-bindings
           ,@body)))))

Пример:

CL-USER 33 > (walker:walk-form
              '(multiple-value-let* (((one two)    (return-1-and-2))
                                     ((three four) (return-3-and-4)))
                 (list one two three four)))
(MULTIPLE-VALUE-BIND (ONE TWO)
    (RETURN-1-AND-2)
  (MULTIPLE-VALUE-BIND (THREE FOUR)
      (RETURN-3-AND-4)
    (PROGN (LIST ONE TWO THREE FOUR))))
4 голосов
/ 02 февраля 2020

Я немного полюбил библиотеку let-plus, которая предлагает макрос let+, который имеет эту опцию (среди прочего):

(let+ (((&values one two) (return-1-and-2))
       ((&values three four) (return-3-and-4))
       (foo (bar))                  ; other examples
       (#(a b c) (some-vector)))    ;
  #| body… |#)
3 голосов
/ 03 февраля 2020

В Serapeum, mvlet*:

Разверните ряд вложенных форм с несколькими значениями.

  (mvlet* ((minutes seconds (truncate seconds 60))
           (hours minutes (truncate minutes 60))
           (days hours (truncate hours 24)))
    (declare ((integer 0 *) days hours minutes seconds))
    (fmt "~d day~:p, ~d hour~:p, ~d minute~:p, ~d second~:p"
         days hours minutes seconds))

https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md#mvlet - остальные-привязки тело-тело

...