在Common Lisp中反转多个值的顺序

时间:2016-01-27 15:28:47

标签: functional-programming lisp common-lisp

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

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

3 个答案:

答案 0 :(得分:5)

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

(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可能具有启发性。

答案 1 :(得分:1)

通过编写一个更高阶函数可以更巧妙地解决这个问题,该函数的输入是返回一些(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-revflip高阶函数的对偶,你可以在一些函数式语言中看到它,它接受二进制函数并返回一个二元函数,该函数就是那个函数,但带有参数逆转。

答案 2 :(得分:0)

要使其像多值绑定一样干净/一致,您可以定义一个宏,如下所示:

(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