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
秒とメーターが一緒に追加されないようにするには、クラスとオブジェクトを使用するだけです。
Gordon S. Novak Jr.の「測定単位の変換」(https://www.cs.utexas.edu/users/novak/units95.html)を参照してください。 – coredump