types - Common Lisp中的类型丰富的编程?

标签 types common-lisp

前几天,我读了一篇有关静态类型的文章(https://bsamuels.net/2013/11/20/static-typing.html),其中描述了一个有趣的概念,称为“类型丰富的编程”,您在其中定义了一些类型,这些类型对于计算机而言只是现有类型的别名(例如整数或浮点数),但是对您来说,它们描述了可以使用这些机器类型表示的不同数量之间的差异(例如,秒和米都可以用 double 表示,但是您当然不希望将它们加在一起)。

我知道Common Lisp是一种动态类型的语言。但是,我也知道,如果我使用thecheck-type,则某些编译器(例如我使用的SBCL)将进行一些有限的类型检查。如何创建类型别名,以便可以为SBCL提供更丰富的类型?或者,如果不是那样的话,那么如何获得类似于Common Lisp中类型丰富的编程的东西?

最佳答案

Common Lisp具有 DEFTYPE 来定义新类型。例如:

(defun secondsp (s)
  (<= 0 s 59))
(deftype seconds ()
  '(and number (satisfies secondsp)))

(let ((s 0))
  (declare (type seconds s))
  (loop
     repeat 60 ;should cause an error when S becomes 60
     do (incf s)
     do (write-char #\.)))

但这并不能阻止您将秒和米加在一起:
(deftype meters ()
  'number)

(let ((s 30)
      (m 15))
  (declare (type seconds s)
           (type meters m))
  (+ s m))
;=> 45

您可以创建一个使用CHECK-TYPE或声明来检查该值在几秒钟内是否为有效值的函数:
;; with CHECK-TYPE and THE
(defun add-seconds (s1 s2)
  (check-type s1 seconds)
  (check-type s2 seconds)
  (the seconds (+ s1 s2)))

;; With declarations
(declaim (ftype (function (seconds seconds) seconds) add-seconds-decl))
(defun add-seconds-decl (s1 s2)
  (+ s1 s2))

但这只会检查该值是否有效。不需要声明变量是否为米,因为该函数仅传递值。
(let ((s1 30)
      (s2 15)
      (m 25))
  (declare (type seconds s1 s2)
           (type meters m))
  (format t "~&S1 + S2 = ~a" (add-seconds-decl s1 s2))
  (format t "~&S1 + M = ~a" (add-seconds-decl s1 m)))
;; S1 + S2 = 45
;; S1 + M = 55

如果要强制执行秒数和计量表永远不要加在一起,则应该只使用类和对象。

关于types - Common Lisp中的类型丰富的编程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36393326/

相关文章:

typescript - TypeScript 中的类型化枚举实例

dependencies - 如何管理常见的 lisp 依赖项?

types - 我应该使用什么类型声明来创建自己的HashMap contains方法?

ruby-on-rails - 为什么 Rails 模型关联结果自然不是 ActiveRecord::Relations?

JSF 核心标签 <c :forEach/> value overflow while iterate

lisp - "Package GLUT does not exist",即使在 Arch Linux 中安装了 cl-opengl

LISP 列表项的总和

common-lisp - 用于解析无效 HTML 的 Common Lisp 包?

python - 相当于 python 习语的常见 lisp

reflection - 以编程方式访问 typespec 的定义