2016-04-04 14 views
7

Ho letto un articolo sulla digitazione statica dell'altro giorno (https://bsamuels.net/2013/11/20/static-typing.html) che descriveva un concetto interessante chiamato "programmazione ricca di tipo", in cui come programmatori definisci tipi che, alla macchina, sono semplicemente alias per tipi esistenti (come interi o float), ma a voi descrivono la differenza tra le diverse quantità che potrebbero essere rappresentate usando quei tipi di macchine (ad esempio, i secondi e i metri potrebbero essere entrambi rappresentati da doppi, ma di certo non vorreste aggiungerli).Programmazione ricca di tipo in Common Lisp?

So che Common Lisp è un linguaggio tipizzato in modo dinamico. Tuttavia, so anche che alcuni compilatori (come quello che uso, SBCL) eseguiranno alcuni controlli di tipo limitato se utilizzo the e check-type. Come posso creare alias di tipo in modo da poter fornire tipi più ricchi a SBCL? Oppure, se no, allora come posso ottenere qualcosa che assomigli ad una programmazione ricca di tipo in Common Lisp?

+0

Vedere [Conversion of Units of Measurement] (https://www.cs.utexas.edu/users/novak/units95.html) di Gordon S. Novak Jr. – coredump

risposta

5

Common Lisp ha DEFTYPE per la definizione di nuovi tipi. Per esempio:

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

Essa non impedisce di aggiungere secondi e metri insieme però:

(deftype meters() 
    'number) 

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

Si potrebbe creare una funzione che utilizza CHECK-TYPE o le dichiarazioni di verificare che il valore è uno valido per secondi:

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

Ma questo controllerà solo che il valore sia valido secondo. Non importa se hai dichiarato la variabile come metri dato che la funzione ha solo passato il valore.

(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 

Se si vuole far rispettare quei secondi e gli indicatori non vengono mai aggiunti insieme, è sufficiente utilizzare classi e oggetti.