代码之家  ›  专栏  ›  技术社区  ›  turingcomplete

Common Lisp中的值函数

  •  29
  • turingcomplete  · 技术社区  · 12 年前

    CommonLisp中的值函数是否只是将多个值打包到一个被调用者破坏的列表中的语法糖?。我之所以这么问,是因为我认为CommonLisp支持“真”多值返回,而不是像python等其他语言那样返回元组或列表。有人刚刚告诉我这只是语法糖,所以我希望有人能解释一下 (type-of (values 1 2 3)) ,输出为 BIT 。我在CommonLisp参考中搜索了它,但在数据类型部分中找不到它。此外,是否有人可以分享一些资源来建议如何在CommonLisp中实现值函数?。非常感谢。

    3 回复  |  直到 12 年前
        1
  •  44
  •   sds Niraj Rajbhandari    6 年前

    CL中的多个值

    这个 语言 Common lisp 在ANSI中有描述 标准 INCITS 226-1994(R2004),有许多 实施 . 每个都可以实现 multiple values 如果它认为合适的话,他们当然可以为他们列出一份清单 (事实上, the Emacs Lisp compatibility layer for CL does just that - 但它是强调和有意的, 公共Lisp实现)。

    意图

    然而 意图 该设施的目的是(至少) 一些)多个值 不考虑 (即,不分配 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
      ...)
    

    MV&类型

    CL会 具有“多值对象”的特殊类型 正因为如此 分配单独的 对象 通过 围绕多个值。从这个意义上说,我们确实可以宣称 values 是句法糖。

    然而,在CL 1中 可以 declare function type 返回 multiple values :

    (declaim (ftype (real &optional real) (values real real)) floor)
    

    这意味着 地板 返回两个值,两者 real s(与返回相反 类型的值 (values real real) )也就是说,在这种情况下 声称滥用符号。

    你的案子

    在您的特定情况下, type-of 是普通函数(即不是宏或特殊运算符)。 您传递给它一个对象1,因为除非您使用 multiple-value-bind 和 朋友,只使用第一个值,因此

    (type-of (values 1 2 3))
    

    与相同

    (type-of 1)
    

    1的类型是 bit .

    PS:控制返回值

    一次使用 价值观 是为了 控制函数的返回值。 通常CL函数的返回值是最后一种形式的值。 有时这是不可取的,例如,最后一个表单返回多个 值,并且您希望函数返回一个值(或无, 喜欢 void 在里面 C ):

    (defun 2values (x y)
      (floor y x))
    (defun 1value (x y)
      (values (floor y x)))
    (defun no-values (x)
      (print x)
      (values))
    
        2
  •  14
  •   Xach    12 年前

    这个 values 函数不仅仅是语法糖,它还可以为调用方生成一个列表,供其进行解构。

    例如,如果调用者只期望一个值,那么它将只从返回多个值的表单中获得一个值(第一个),而不是列表。自从 type-of 只接受一个值作为参数,它将为您提供第一个值1的类型。1属于类型 BIT .

    每个CommonLisp实现都可以自由地追求自己的策略来实现多个值。我从Frode Fjeld写的关于他的实现Movitz如何处理它的文章中学到了很多 The Movitz development platform ,第2.5节。

        3
  •  1
  •   Sylwester    12 年前

    如果你做了一个CL实现,你可以用列表来实现它,只要它符合规范。你需要处理一个特定的值,你需要一些方法来标记0,2..n值,而其他函数需要理解格式和打印可以以与其他实现相同的方式显示它。

    最有可能 values 它的姊妹函数是一种优化,其中实现使用堆栈,而不是将值考虑到列表结构中,以便在下一级中对其进行销毁。在过去,RAM和CPU不会被浪费,这是非常重要的,但我怀疑如果你使用,你会发现真正的麻烦 destructuring-bind 而不是 multiple-value-bind 今天

    CommonLisp与Scheme在积极的方向上有很大的不同,你可以创建一个函数,例如。 floor 在它的计算中,除了商的答案之外,剩下的都是,同时返回所有值,但你可以使用它,就像它只返回第一个值一样。我真的很怀念写Scheme的时候,因为它要求你有一个 call-with-values 类似于 multiple-value-call 或句法糖样 let-values 为了处理所有返回的值,如果您只需要其中一个值,那么您将再次创建三个版本。