'Typing variables in Common Lisp
I read that CL supports optional typing (as in the language has this feature) which I would assume allos for faster code in many cases, but I can't seem to find anything about actually writing typed code. Is it possible to explicitly type code instead of using hacks? (for example, #'vector
generates a simple-vector
, kinda reminds me of |0
in JS to coerce to an integer)
Or maybe since types are actually CLOS classes (they are, right?) you simply have to #'make-instance
an object of type, say, 'integer
?
Solution 1:[1]
Common Lisp allows to define types and to declare types for variables, functions, ...
Types are independent from classes - classes are also types, but types can express more (like the range of integers, the size of an array, the element types of an array, ...).
Declaring types may serve a lot of different purposes:
- omit runtime type checks in optimized code
- generation of specialized instructions in optimized code
- compile-time type checks
- optimize allocation of data structures
- runtime type checks
- documentation
Thus the effects of declaring types with certain compiler settings (debug, space, speed, compilation-speed, safety, ..) is not very simple. A Lisp system may ignore much of the declarations or use them widely. The effects can be very different. In some combination of compiler settings declaring a type may make the code a lot slower, in others it may make it a lot faster.
Also, compilers might be able to do some amount of type inference.
A simple declaration might look like this:
(defun add-integer (a b)
(declare (integer a b))
(the integer (+ a b)))
The Lisp system can now do one or more of the following:
- ignore the declaration
- add runtime checks that
a
andb
are integers and that the result of the + operation is actually an integer (and not a float, rational or complex number) - omit runtime checks for the
+
operation - generate code for a specialized
+
operation, which only works on integers - do compile-time type checks
Typical compiler settings to achieve above would be:
- safety = 3
- safety = 0
- safety = 0 and speed = 3
But the exact settings and their meaning might differ and should be documented in the specific Lisp implementation manual.
The types are documented in the ANSI Common Lisp Standard. See Types and Classes.
For the compiler settings see for example: SBCL Compiler or LispWorks, The Compiler.
To study the effect of compilation of type declared code one can use disassemble and time.
Solution 2:[2]
For performance tuning see https://lispcookbook.github.io/cl-cookbook/performance.html
For compile-time type warnings see https://lispcookbook.github.io/cl-cookbook/type.html
You can give type hints like this:
(defun max-with-type (a b)
(declare (optimize (speed 3) (safety 0)))
(declare (type integer a b))
(max a b))
and use the
:
(defun do-some-arithmetic (x)
(declare (optimize (speed 3) (debug 0) (safety 0)))
(the fixnum (+ x (square x))))
Using declaim will also give more type warnings at compile time.
It is possible to type variables:
(declaim (type (string) *name*))
(defparameter *name* "book")
We can compose types ((or null string)
) and use our owns (declared with deftype
).
You can declare function types with declaim
, or with declare
inside the function:
(declaim (ftype (function (fixnum) fixnum) add))
;; ^^input ^^output [optional]
(defun add (n)
(+ n 1))
With this we get nice type warnings at compile time.
If we change the function to erroneously return a string instead of a fixnum, we get a warning:
(defun add (n)
(format nil "~a" (+ n 1)))
; caught WARNING:
; Derived type of ((GET-OUTPUT-STREAM-STRING STREAM)) is
; (VALUES SIMPLE-STRING &OPTIONAL),
; conflicting with the declared function return type
; (VALUES FIXNUM &REST T).
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Ehvince |