【问题标题】:Inverting order of multiple values in Common Lisp在 Common Lisp 中反转多个值的顺序
【发布时间】:2016-01-27 15:28:46
【问题描述】:

我一直在思考以下问题。假设我正在处理一个返回多个值的函数,例如truncate。有没有巧妙的方法来反转返回值的顺序?我说的是比例如更聪明的东西

(multiple-value-bind (div rem) (truncate x y)
  (values rem div))

【问题讨论】:

    标签: functional-programming lisp common-lisp


    【解决方案1】:

    我不知道这有多聪明,但这就是你想要的:

    (reverse (multiple-value-list (the-function-that-returns-multiple-values)))
    

    multiple-value-list 是这里的关键。

    要将这些作为单独的值再次返回,请使用values-list

    (values-list (reverse (multiple-value-list (the-function-that-returns-multiple-values))))
    

    This whole page 可能很有启发性。

    【讨论】:

    • 是的,实际上这就是我在此期间想出的,只是装扮成一个宏: (defmacro reverse-values (sexp) `(apply #'values (reverse (multiple-value-list ,性别)))))
    • 澄清一下,蒂姆,我的意思是会反转值 将它们作为单独的 Lisp 返回值返回。但是你给出了本质,所以我把它标记为答案。谢谢。
    • 我已经用更好的结构修改了答案来做你想做的事。
    • 谢谢,蒂姆。我喜欢这样比明确应用 #'values 更好。
    【解决方案2】:

    这个问题可以通过编写一个高阶函数更巧妙地解决,它的输入是一个返回一些(values a b)的函数,它返回一个调用该函数的函数,但返回(values b a)。换句话说,一个值反转组合器:

    (defun val-rev (function)
      (lambda (&rest args)
        (multiple-value-bind (a b) (apply function args)
           (values b a))))
    

    虽然在这个函数的定义中,我们正在做你不想要的繁琐的事情(用m-v-bind 捕获值并用values 反转),但它被封装在组合器中,只是一个实现细节。它可能比构造一个值列表并反转它更有效。此外,它专门针对前两个值。如果一个函数返回四个值A B C D,那么反转multiple-value-list意味着前两个返回值将是C D。但是,如果我们只是绑定前两个并将它们反转,那么我们赌B A。反转前两个(或仅两个)值显然与反转所有值不同。

    演示:

    [1]> (truncate 17 3)
    5 ;
    2
    [2]> (funcall (val-rev #'truncate) 17 3)
    2 ;
    5
    

    请注意,在 Lisp-1 方言中,调用会丢失 #'funcall 的附加噪音,简化为:((val-rev truncate) 17 3)

    val-rev 是您在某些函数式语言中看到的 flip 高阶函数的对偶,它接受一个二进制函数并返回一个二进制函数,即该函数,但参数相反。

    【讨论】:

      【解决方案3】:

      要让它像多值绑定一样干净/一致,您可以定义如下宏:

      (defmacro reverse-multiple-value-bind (args f &rest body) 
        `(multiple-value-bind ,(reverse args) 
            ,f 
            ,@body))
      

      那么你有

      >> (multiple-value-bind (x y) (floor 3.7) (print x) (print y))
      3 
      0.70000005
      

      > (reverse-multiple-value-bind (x y) (floor 3.7) (print x) (print y))
      0.70000005 
      3 
      

      【讨论】:

      • 好吧,这不是很有用,因为我已经有了multiple-value-bind 并且在你的宏中我仍然需要明确地对绑定值做一些事情,所以为什么要打扰。我的问题是特别关于以相反的顺序返回多个值,而不是关于以相反的顺序绑定它们。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-10
      • 1970-01-01
      • 2011-03-31
      • 2012-08-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多