2016-04-04 82 views
7

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

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

+0

请参阅Gordon S. Novak Jr的[计量单位转换](https://www.cs.utexas.edu/users/novak/units95.html)。 – coredump

回答

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 

如果您想要强制执行秒和米永远不会加在一起,您应该只使用类和对象。