Common Lisp предлагает такое типовое тестирование при времени выполнения . У него сложная система типов, но она не используется, как вы могли бы привыкнуть в статически типизированном языке. Макрос check-type
принимает typespec , который может быть встроенной спецификацией или определенной макросом deftype
, Ограничения, которые можно выразить с помощью спецификаций типов, относятся к функции предиката, написанной на языке хоста, то есть, что все, что вы можете проверить во время выполнения, может быть критерием того, что составляет ваш новый тип.
Рассмотрим этот пример:
(defun is-nothing (val)
(when (stringp val)
(string= val "nothing")))
(deftype strange-range ()
"A number between 0 and 100 inclusive, or the string \"nothing\"."
'(or (integer 0 100)
(satisfies is-nothing)))
Это определяет тип, называемый "странный диапазон". Теперь протестируйте несколько значений:
CL-USER> (let ((n 0))
(check-type n strange-range))
NIL
CL-USER> (let ((n 100))
(check-type n strange-range))
NIL
CL-USER> (let ((n "nothing"))
(check-type n strange-range))
NIL
CL-USER> (let ((n 101))
(check-type n strange-range))
Последний запускает отладчик со следующим сообщением:
The value of N should be of type STRANGE-RANGE.
The value is: 101
[Condition of type SIMPLE-TYPE-ERROR]
Этот провоцирует тот же результат:
CL-USER> (let ((n "something"))
(check-type n strange-range))
Ограничения, которые можно наложить таким образом, являются выразительными, но они не служат той же цели, что сложные системы типов языков, таких как Haskell или Scala. Хотя определения типов могут уговорить компилятор Common Lisp выдавать код, более адаптированный и эффективный для типов операндов, приведенные выше примеры являются более кратким способом написания проверок типов во время выполнения.