【翻译】Lisp.多值(Multiple values)

17 views
Skip to first unread message

panfei

unread,
Oct 22, 2012, 6:57:21 AM10/22/12
to lisp-...@googlegroups.com

有人曾经说过,为了强调函数式编程语言的重要性,都要说每个Lisp表达式都返回一个值。现在事情没有那么简单了;在Common Lisp中,一个表达式可以返回0个或多个值。返回值的最大个数根据实现的不同而不同,但是至少是19个。


多值允许函数计算并返回几个东西,并且不需要建立一个结构来保存它们。比如,内置的函数get-decoded-time返回当前的时间,这个时间用9个值来表示:秒,分钟,小时,日期,月,日,还有其它两个东西。


多值也是的我们在写函数的时候可以区分找到nil和找不到一些东西的情况。这也就是为什么gethash返回两个值。因为它使用第二个值来标识是成功或是失败,我们可以在一个哈希表表中存储nil,就像是存储其它值一样。


函数values返回多值。他就是返回了你传递给它的参数:

[plain] view plaincopy
  1. [30]> (values 'a nil (+ 2 1))  
  2. A ;  
  3. NIL ;  
  4. 3  

如果一个values表达式是一个函数中最后被求值的,那么它的返回值也就变成这个函数的返回值。多值在多个返回中被完整地传递:
[plain] view plaincopy
  1. [32]> ((lambda () ((lambda () (values 1 2)))))  
  2. 1 ;  
  3. 2  

然而,有时候只需要一个值,除了第一个外其它的都要被舍弃掉:

[plain] view plaincopy
  1. [33]> (let ((x (values 1 2))) x)  
  2. 1  

不给values任何参数,它可能不会返回任何值。这种情况下,如果你想从中获取一个值,你就会获得nil:

[plain] view plaincopy
  1. [36]> (values)  
  2.   
  3. [37]> (let ((x (values))) x)  
  4. NIL  

要想接收到多值,我们使用multiple-value-bind函数:

[plain] view plaincopy
  1. [39]> (multiple-value-bind (x y z) (values 1 2 3) (list x y z))  
  2. (1 2 3)  
  3. [40]> (multiple-value-bind (x y z) (values 1 2) (list x y z))    
  4. (1 2 NIL)  

如果变量比值多,那么多出来的就是nil了。如果值比变量多,那么多于的值就会被丢弃掉。所以如果我们想只打印时间,我们就可以这样写:

[plain] view plaincopy
  1. [42]> (multiple-value-bind (s m h) (get-decoded-time) (format nil "~A:~A:~A" h m s))  
  2. "16:5:4"  

你可以通过multiple-value-call将多值应用到第二个函数上:

[plain] view plaincopy
  1. [43]> (multiple-value-call #'+ (values 1 2 3))  
  2. 6  

还有一个函数:multiple-value-list:

[plain] view plaincopy
  1. [44]> (multiple-value-list (values 'a 'b 'c))  
  2. (A B C)  

其实这和调用multiple-value-call,将其第一个参数设置为#'list是一样的效果。

--
不学习,不知道

Reply all
Reply to author
Forward
0 new messages