Functional programming 公共Lisp中多个值的反转顺序

Functional programming 公共Lisp中多个值的反转顺序,functional-programming,lisp,common-lisp,Functional Programming,Lisp,Common Lisp,我一直在考虑以下问题。假设我正在处理一个返回多个值的函数,例如truncate。有没有一种聪明的方法来颠倒返回值的顺序?我说的是比例句更聪明的事 (multiple-value-bind (div rem) (truncate x y) (values rem div)) 我不知道这有多聪明,但这是你想要的: (reverse (multiple-value-list (the-function-that-returns-multiple-values))) 这里是关键 要将这些值作为单

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

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

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

(reverse (multiple-value-list (the-function-that-returns-multiple-values)))
这里是关键

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


也许会有启发。

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

(reverse (multiple-value-list (the-function-that-returns-multiple-values)))
这里是关键

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


这可能很有启发性。

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

(defun val-rev (function)
  (lambda (&rest args)
    (multiple-value-bind (a b) (apply function args)
       (values b a))))
虽然在这个函数的定义中,我们正在做你不想做的繁琐的事情(用
m-v-bind
捕获值,用
反转),但它被封装在combinator中,只是一个实现细节。这可能比考虑一个值列表并将其反转更有效。此外,它专门针对前两个值。如果函数返回四个值,
a B C D
,则反转
多值列表
意味着前两个返回值将是
C D
。然而,如果我们只绑定前两个并反转它们,那么我们就打赌
ba
。反转前两个(或仅两个)值显然与反转所有值不同

演示:

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


val rev
是一些函数式语言中所见的
flip
高阶函数的一种对偶函数,它接受一个二进制函数并返回一个二进制函数,即该函数,但是参数相反。

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

(defun val-rev (function)
  (lambda (&rest args)
    (multiple-value-bind (a b) (apply function args)
       (values b a))))
虽然在这个函数的定义中,我们正在做你不想做的繁琐的事情(用
m-v-bind
捕获值,用
反转),但它被封装在combinator中,只是一个实现细节。这可能比考虑一个值列表并将其反转更有效。此外,它专门针对前两个值。如果函数返回四个值,
a B C D
,则反转
多值列表
意味着前两个返回值将是
C D
。然而,如果我们只绑定前两个并反转它们,那么我们就打赌
ba
。反转前两个(或仅两个)值显然与反转所有值不同

演示:

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


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

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

(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


要使其与多值绑定一样干净/一致,可以定义如下宏:

(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


是的,实际上这就是我当时想到的,只是打扮成一个宏:(defmacro reverse values(sexp)`(apply#'values(reverse(multiple value list,sexp)))为了澄清,Tim,我的意思是将值反转并作为单独的Lisp返回值返回。但你给出了本质,所以我把它标记为答案。谢谢。我已经用一个更好的结构修改了答案,来做你想做的。谢谢,蒂姆。比起显式地应用
#值,我更喜欢它。是的,实际上这就是我在这段时间里想到的,只是把它打扮成一个宏:(defmacro reverse values(sexp)`(apply#'values(reverse(multiple value list,sexp)))澄清一下,蒂姆,我的意思是将值反转并将它们作为单独的Lisp返回值返回。但你给出了本质,所以我把它标记为答案。谢谢。我已经用一个更好的结构修改了答案,来做你想做的。谢谢,蒂姆。比起显式应用
#值
,我更喜欢这样做。好吧,这不是很有用,因为我已经有了
多值绑定
,在您的宏中,我仍然需要显式地对绑定值做一些事情,所以为什么要麻烦呢。我的问题是以相反的顺序返回多个值,而不是以相反的顺序绑定它们。好吧,这不是很有用,因为我已经有了
多值绑定
,并且在您的宏中,我仍然需要显式地对绑定的值执行一些操作,所以为什么要麻烦呢。我的问题是以相反的顺序返回多个值,而不是以相反的顺序绑定它们。