在 Common Lisp 中反转多个值的顺序
Inverting order of multiple values in Common Lisp
我一直在思考以下问题。假设我正在处理一个返回多个值的函数,例如 truncate
。有没有一种聪明的方法可以颠倒返回值的顺序?我说的是比例如
更聪明的东西
(multiple-value-bind (div rem) (truncate x y)
(values rem div))
我不知道这有多聪明,但这就是你想要的:
(reverse (multiple-value-list (the-function-that-returns-multiple-values)))
multiple-value-list这里是关键。
为了 return 这些再次作为单独的值,使用 values-list:
(values-list (reverse (multiple-value-list (the-function-that-returns-multiple-values))))
This whole page 可能很有启发性。
这个问题可以通过编写一个高阶函数来更巧妙地解决,该函数的输入是 return 一些 (values a b)
的函数,并且 return 是调用该函数的函数, 但 returns (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
反转)这是封装在组合器中的,只是一个实现细节。它可能比整理一个值列表并将其反转更有效。此外,它专门针对前两个值。如果一个函数 return 有四个值 A B C D
,那么反转 multiple-value-list
意味着前两个 return 值将是 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
高阶函数的对偶,它采用二元函数,而 returns 是一个二元函数函数,但参数相反。
要将其作为 clean/consistent 作为多值绑定,您可以定义如下宏:
(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
我一直在思考以下问题。假设我正在处理一个返回多个值的函数,例如 truncate
。有没有一种聪明的方法可以颠倒返回值的顺序?我说的是比例如
(multiple-value-bind (div rem) (truncate x y)
(values rem div))
我不知道这有多聪明,但这就是你想要的:
(reverse (multiple-value-list (the-function-that-returns-multiple-values)))
multiple-value-list这里是关键。
为了 return 这些再次作为单独的值,使用 values-list:
(values-list (reverse (multiple-value-list (the-function-that-returns-multiple-values))))
This whole page 可能很有启发性。
这个问题可以通过编写一个高阶函数来更巧妙地解决,该函数的输入是 return 一些 (values a b)
的函数,并且 return 是调用该函数的函数, 但 returns (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
反转)这是封装在组合器中的,只是一个实现细节。它可能比整理一个值列表并将其反转更有效。此外,它专门针对前两个值。如果一个函数 return 有四个值 A B C D
,那么反转 multiple-value-list
意味着前两个 return 值将是 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
高阶函数的对偶,它采用二元函数,而 returns 是一个二元函数函数,但参数相反。
要将其作为 clean/consistent 作为多值绑定,您可以定义如下宏:
(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