在Common Lisp中,这些值是否只是用于将多个值打包到一个被调用者解构的列表中的语法糖?我问,因为我认为Common Lisp支持" true"多值返回而不是像其他语言一样返回元组或列表,例如python。有人告诉我它只是语法糖,所以我希望有人能够解释它。为了尝试理解values函数返回的类型,我输入了(type-of (values 1 2 3))
,输出为BIT
。我在Common Lisp参考中搜索了这个,但我无法在数据类型部分中找到它。此外,任何人都可以共享一些资源,建议如何在Common Lisp中实现值函数吗?谢谢。
答案 0 :(得分:38)
语言Common lisp在ANSI 标准 INCITS 226-1994(R2004)中描述,并且具有许多实现。 每个人都可以按照自己的意愿实施multiple values, 当然,他们被允许为他们列出清单 (事实上,the Emacs Lisp compatibility layer for CL does just that - 但是,强调和故意,不一个Common Lisp实现。)
但是,此工具的 intent 是允许传递(至少一些)多个值而不需要(即,不分配heap内存)和我所知道的所有CL实现都是这样做的。 从这个意义上讲,多值设施是优化。
当然,对于不同的平台和场景,此功能的实现可能会有很大差异。例如,前几个(比如,20 - required by the standard)存储在线程局部向量的静态中,接下来的几个(1000?)在堆栈上分配,其余的(如果需要)在堆上分配作为矢量或列表。
,例如,函数floor
返回两个值。
如果你写
(setq a (floor 10 3))
你只捕获第一个并丢弃第二个,你需要写
(setf (values q r) (floor 10 3))
捕获两个值。这类似于other languages可能表达的内容
q,r = floor(10,3)
使用tuples,除了CL 不分配内存以传递(只是几个)多个值,而其他语言经常这样做。
IOW,我们可以将多个值视为一个短暂的结构。
请注意,CL可以将多个值转换为列表:
(destructuring-bind (q r) (multiple-value-list (floor 10 3))
; use q & r here
...)
而不是更有效和简洁
(multiple-value-bind (q r) (floor 10 3)
; use q & r here
...)
CL确实不具有“多值对象”的特殊类型,因为它不分配单独的对象来传递多个值。在这个意义上,人们可以确实声称values
是语法糖。
但是,在CL中,一个可以声明function type返回multiple values:
(declaim (ftype (real &optional real) (values real real)) floor)
这意味着floor
返回两个值real
s(而不是返回类型(values real real)
的值),即,在这种情况下,可能会声称滥用符号。
在您的特定情况下,type-of
是普通函数(即,不是宏或特殊运算符)。
你传递一个对象1,因为,除非你使用multiple-value-bind
和朋友,否则只使用第一个值,所以
(type-of (values 1 2 3))
与
相同(type-of 1)
且类型1为bit
。
values
的一个用途是
控制函数的返回值。
通常,CL函数的返回值是最后一种形式的返回值。
有时它是不可取的,例如,最后一个表格返回多个
值,您希望函数返回一个值(或者没有,例如C
中的void
):
(defun 2values (x y)
(floor y x))
(defun 1value (x y)
(values (floor y x)))
(defun no-values (x)
(print x)
(values))
答案 1 :(得分:12)
values
函数不仅仅是用于为调用者进行解构的列表的语法糖。
例如,如果调用者只需要一个值,它将从返回多个值的表单中只获得一个值(第一个),而不是列表。由于type-of
只接受一个值作为参数,因此它为您提供第一个值的类型,1。类型为BIT。
每个Common Lisp实现都可以自由地实现自己的策略来实现多个值。我从Frode Fjeld所写的关于他的实现如何在The Movitz development platform第2.5节中处理它的方法中学到了很多东西。
答案 2 :(得分:1)
如果你进行CL实现,你可以用列表实现它,只要它符合规范。你需要处理一个特定的值,你需要一些方法来标记零,2..n值,其他函数需要理解格式和打印可以像其他品牌一样显示它。
最有可能values
及其姐妹函数是一种优化,其中实现使用堆栈而不是将值传递给列表结构,只是为了让它在下一级别进行解构。在没有浪费RAM和CPU的旧时代,这非常重要,但我怀疑如果你今天使用destructuring-bind
代替multiple-value-bind
,你会发现真正的麻烦。
Common Lisp与Scheme的不同之处在于你可以创建一个函数,例如。 floor
除了商数答案之外,计算结果中的余数最终会返回所有值,但是您可以使用它,就像它只返回第一个值一样。我非常想念有时候编写Scheme,因为它要求你有一个类似于call-with-values
的{{1}}或像multiple-value-call
这样的语法糖来处理所有返回的值,这些值再次让你最终得到制作三个版本,以防您只需要其中一个值。