2016-04-04 31 views
7

Przeczytałem artykuł o statycznym typowaniu w innym dniu (https://bsamuels.net/2013/11/20/static-typing.html), który opisał interesującą koncepcję zwaną "programowaniem bogatym w typ", gdzie jako programista zdefiniowano typy, które dla maszyny są po prostu aliasami dla istniejących typów (takich jak liczby całkowite lub zmiennoprzecinkowe), ale dla ciebie opisują różnicę między różnymi wielkościami, które mogą być reprezentowane za pomocą tych typów maszyn (np. sekundy i metry mogą być reprezentowane przez podwójne, ale na pewno nie chciałbyś ich dodać razem).Programowanie bogate w typ w Common Lisp?

Wiem, że Common Lisp jest językiem napisanym dynamicznie. Jednak wiem również, że niektóre kompilatory (takie jak ten, którego używam, SBCL) wykonają pewne ograniczone sprawdzanie typu, jeśli używam the i check-type. Jak mogę utworzyć aliasy typów, aby zapewnić bogatsze typy SBCL? Lub, jeśli nie to, to w jaki sposób mogę uzyskać coś, co wygląda podobnie do programowania bogatego w typ w Common Lisp?

+0

Zobacz [Konwersja jednostek miary] (https://www.cs.utexas.edu/users/novak/units95.html) autorstwa Gordona S. Novaka Jr. – coredump

Odpowiedz

5

Common Lisp ma DEFTYPE do definiowania nowych typów. Na przykład:

(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 #\.))) 

To nie uniemożliwi dodanie razem sekund i metrów choć:

(deftype meters() 
    'number) 

(let ((s 30) 
     (m 15)) 
    (declare (type seconds s) 
      (type meters m)) 
    (+ s m)) 
;=> 45 

Można utworzyć funkcję, która używa CHECK-TYPE lub oświadczenia, aby sprawdzić czy wartość jest ważny jeden na sekundy:

;; 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)) 

Ale to tylko sprawdzi, czy wartość jest ważna sekunda. Nie ma znaczenia, czy zadeklarowano, że zmienna jest licznikiem, ponieważ funkcja ma tylko wartość.

(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 

Jeśli chcesz wymusić, że sekundy i metry nigdy nie są dodawane razem, powinieneś po prostu użyć klas i obiektów.