Accessor VALUES作为返回值无效或可忽略的最后一种定义形式

时间:2013-05-29 09:07:02

标签: lisp common-lisp return-value

当阅读其他开发人员编写的Commom Lisp代码时,我注意到其中一些代码 调用VALUES访问器而不提供返回值无效或可忽略的最后定义形式的任何参数。

示例:

(defun definition-whose-return-values-are-neglectable ()
  ... Some s-expressions ...
  (values))

是否有任何优势(对于编译器,在性能等方面)将此表单添加为这些类型的定义中的最后一个表达式?

3 个答案:

答案 0 :(得分:3)

一个有用的事情是,在REPL中调用函数时,不会打印出随机值。这在与系统交互时非常方便。

答案 1 :(得分:3)

打印

Lisp中没有invisible,因此无论函数返回什么,都将由REPL的P(打印)部分打印。这意味着如果您的打印设置不合适,系统可能会打印许多屏幕(您甚至可能会遇到令人困惑的堆栈溢出错误,因为print-circlenil且返回值为循环结构。)< / p>

汇编

编译器可以进行一些优化(特定编译器在实践中可能会或可能不会实际执行);例如,它可能会将函数标记为不返回任何有趣的内容,然后将(setq var (my-func))等表达式编译为(progn (my-func) (setq var nil))

如果编译器可以证明该函数没有副作用,并以(values)结束,那么编译器可以完全放弃它的调用。

文档

计算机编程的一个重要方面是您的代码将被其他人(包括您自己)读取,并且在函数末尾添加(values)会告诉读者该函数仅被调用副作用。 / p>

答案 2 :(得分:3)

(values)最后一种形式的优点或主要用例是:

  • 当返回值对于定义无意义时自我记录代码
  • 通常,避免开发工具处理或保留引用 被忽视或不必要的结果;
    特别:
    • 要避免在REPL中打印长序列或无限序列,以防万一 *print-circle*设置为t*print-length*设置为nil*print-level*设置为nil, 或任何特定于实现的参数
    • REPL将*设置为nil,因为无值被视为 nil,并将/设置为空列表
    • 在Allegro CL的IDE中,ListenersTrace dialog 保持对结果的引用,直到它们被清除 1
    • 在LispWorks的IDE中,Tracer工具保留了对结果的引用 输出数据视图,直到它们被清除
    • 在SLIME中,REPL会在presentations中保留对结果的引用 直到他们被清除

非优势/非优势:

  • 有些编译器会生成少量指令,有些会生成更多指令,但除非 你正在处理字节和/或周期,这是可以忽略不计的
  • 您已经不需要返回任何值,例如:
    • 当您希望来电者区分返回值的数量时 这可能也暴露了定义的糟糕设计
    • 当结果应该用于 multiple-value-call表格
      这可能也暴露了调用者的糟糕设计,这实际上是有一面的 形式之间的影响
      除了摆脱副作用或允许这样做之外,这里除此之外几乎没有什么可做的 副作用发生在整个multiple-value-call
    • 之前或之后

问题:

  • 通常,它会从定义中禁用尾调用优化 但是,足够智能的编译器可能会检测到对无值定义的尾调用, 通常在ftype declare s / declaim s的帮助下, 并在这些调用中应用优化
    这并非没有其他定义被改变的风险,所以我的猜测是这样的 没有实现吗

1。您可以通过设置历史记录清除Allegro CL中的监听器历史记录 大纲的内容为空列表:

(setf (cg:range (cg:find-component
                 :history-outline
                 (first (cg:toolbars ide.base:*listener-window*))))
      '())