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

fou*_*ric 8 types common-lisp

我前几天读了一篇关于静态类型的文章(https://bsamuels.net/2013/11/20/static-typing.html),描述了一个名为"类型丰富的编程"的有趣概念,你作为程序员定义对于机器而言,这些类型只是现有类型的别名(例如整数或浮点数),但对于它们,它们描述了可以使用这些机器类型表示的不同数量之间的差异(例如,秒和米都可以由双打,但你肯定不想把它们加在一起).

我知道Common Lisp是一种动态类型的语言.但是,我也知道一些编译器(例如我使用的编译器,SBCL)会做一些有限的类型检查,如果我使用thecheck-type.如何创建类型别名,以便为SBCL提供更丰富的类型?或者,如果不是这样,那么我怎样才能在Common Lisp中获得类似于类型丰富的编程的东西呢?

jki*_*ski 6

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 #\.)))
Run Code Online (Sandbox Code Playgroud)

它不会阻止您在一起添加秒和米:

(deftype meters ()
  'number)

(let ((s 30)
      (m 15))
  (declare (type seconds s)
           (type meters m))
  (+ s m))
;=> 45
Run Code Online (Sandbox Code Playgroud)

您可以创建一个使用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))
Run Code Online (Sandbox Code Playgroud)

但那只会检查该值是否有效.如果您将变量声明为米,则无关紧,因为函数仅传递了值.

(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
Run Code Online (Sandbox Code Playgroud)

如果你想强制执行秒和米从不加在一起,你应该只使用类和对象.