【问题标题】:Typing variables in Common Lisp在 Common Lisp 中键入变量
【发布时间】:2017-05-31 09:05:07
【问题描述】:

我读到 CL 支持可选类型(因为该语言具有此功能),在许多情况下我会假设 allos 用于更快的代码,但我似乎找不到任何关于实际编写类型代码的信息。是否可以显式键入代码而不是使用黑客? (例如,#'vector 生成一个simple-vector,有点让我想起 JS 中的 |0 强制转换为整数)

或者也许因为类型实际上是 CLOS 类(它们是,对吗?)你只需要 #'make-instance 一个类型的对象,比如说,'integer

【问题讨论】:

  • 也许(declare (type integer var)) 其中var 是绑定到值30 的变量(例如)?
  • 类型与 CLOS 是分开的。您可以使用DECLARE/PROCLAIM/DECLAIM 来声明变量/函数的类型。对于结构或类插槽,您可以使用:TYPE 关键字,对于数组,您可以使用:ELEMENT-TYPE。例如,(let ((x 10)) (declare (type integer x)) ...)。声明类型时实际发生的情况取决于实现和优化设置。通常你需要提高速度来获得优化的代码,或者安全来进行类型检查。
  • 类型不是 CLOS 类/对象。所有类都有对应的类型,但反之则不然。您无法保证代码在类型提示下运行得更快。 IMO 这意味着您可以在需要这些东西时编写代码并输入安全/速度提示,但这样做总是过早的优化

标签: types common-lisp typing typed


【解决方案1】:

Common Lisp 允许定义类型和声明变量、函数的类型...

类型独立于类——类也是类型,但类型可以表达更多(如整数的范围、数组的大小、数组的元素类型……)。

声明类型可能有很多不同的用途:

  • 在优化代码中省略运行时类型检查
  • 在优化代码中生成专用指令
  • 编译时类型检查
  • 优化数据结构的分配
  • 运行时类型检查
  • 文档

因此,使用某些编译器设置(调试、空间、速度、编译速度、安全性......)声明类型的效果不是很简单。 Lisp 系统可能会忽略大部分声明或广泛使用它们。效果可能非常不同。在声明类型的编译器设置的某些组合中,可能会使代码变慢很多,而在另一些组合中,它可能会使代码变快。

此外,编译器可能能够进行一定数量的类型推断。

一个简单的声明可能如下所示:

(defun add-integer (a b)
  (declare (integer a b))
  (the integer (+ a b)))

Lisp 系统现在可以执行以下一项或多项操作:

  1. 忽略声明
  2. 添加运行时检查ab 是 整数并且 + 操作的结果实际上是 整数(而不是浮点数、比率或复数)
  3. 省略 + 操作的运行时检查
  4. 为专门的 + 操作生成代码,该操作仅适用于整数
  5. 进行编译时类型检查

实现该目标的典型编译器设置是:

  1. 安全 = 3
  2. 安全 = 0
  3. 安全 = 0,速度 = 3

但确切的设置及其含义可能有所不同,应记录在 Lisp 实施手册中。

这些类型记录在 ANSI Common Lisp 标准中。见Types and Classes

有关编译器设置,请参见例如:SBCL CompilerLispWorks, The Compiler

要研究类型声明代码的编译效果,可以使用disassembletime

【讨论】:

  • 感谢您的详细解答!当我需要编写快速代码时(我认为我需要这样做以说服我叔叔在他的启动项目中使用 CL)我会采纳你的建议
  • the 做了什么?它是否返回某种类型的值?
  • 它返回一个整数
  • 所以(the string "Hello") => 字符串,(the simple-vector #(1 2 3)) => 简单向量等?
【解决方案2】:

有关性能调整,请参阅https://lispcookbook.github.io/cl-cookbook/performance.html

编译时类型警告https://lispcookbook.github.io/cl-cookbook/type.html

你可以像这样给出类型提示:

(defun max-with-type (a b)
    (declare (optimize (speed 3) (safety 0)))
    (declare (type integer a b))
    (max a b))

并使用the:

(defun do-some-arithmetic (x)
  (declare (optimize (speed 3) (debug 0) (safety 0)))
  (the fixnum (+ x (square x))))

使用 declaim 还会在编译时给出更多类型警告。

可以输入变量:

(declaim (type (string) *name*))
(defparameter *name* "book")

我们可以组合类型 ((or null string)) 并使用我们自己的类型(用 deftype 声明)。

您可以在函数内使用declaimdeclare 声明函数类型:

(declaim (ftype (function (fixnum) fixnum) add))
;;                         ^^input ^^output [optional]
(defun add (n)
    (+ n  1))

这样我们在编译时会得到很好的类型警告。

如果我们将函数更改为错误地返回字符串而不是 fixnum,我们得到一个警告:

(defun add (n)
    (format nil "~a" (+ n  1)))
; caught WARNING:
;   Derived type of ((GET-OUTPUT-STREAM-STRING STREAM)) is
;     (VALUES SIMPLE-STRING &OPTIONAL),
;   conflicting with the declared function return type
;     (VALUES FIXNUM &REST T).

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-18
    • 2019-09-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多