2016-04-04 44 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 

如果您想要強制執行秒和米永遠不會加在一起,您應該只使用類和對象。