【问题标题】:How to format a nested multiple-value-bind the let way?如何格式化嵌套的多值绑定?
【发布时间】:2020-05-18 01:59:23
【问题描述】:

最近,我经常嵌套几个返回多个值的函数。然而,与 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))

?

【问题讨论】:

    标签: lisp common-lisp let multiple-value


    【解决方案1】:

    库中可能有类似的结构。

    注意它更类似于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))))
    

    【讨论】:

    • 感谢您的宏以及指出let* 的类比。您是否有可能在第二个列表中有错字,即 multiple-let* 而不是 multiple-value-let*?
    【解决方案2】:

    我越来越喜欢 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】:

    在 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-rest-bindings-body-body

    【讨论】:

      猜你喜欢
      • 2021-01-19
      • 2012-05-04
      • 2021-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-23
      • 1970-01-01
      相关资源
      最近更新 更多