我前几天阅读了一篇关于静态类型的文章(https://bsamuels.net/2013/11/20/static-typing.html),该文章描述了一个名为“类型丰富的编程”的有趣概念,作为程序员,您作为程序员定义的类型对于机器来说只是别名现有的类型(如整数或浮点数),但对你来说,它们描述了可以使用这些机器类型表示的不同数量之间的差异(例如,秒和米都可以用双精度表示,但你肯定不想添加他们在一起)。
我知道Common Lisp是一种动态类型的语言。但是,我也知道如果我使用the
和check-type
,某些编译器(例如我使用的编译器,SBCL)会进行一些有限的类型检查。如何创建类型别名,以便为SBCL提供更丰富的类型?或者,如果不是这样,那么我怎样才能在Common Lisp中获得类似于类型丰富的编程的东西呢?
答案 0 :(得分:5)
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
如果你想强制执行秒和米从不加在一起,你应该只使用类和对象。