type templates
4.0.0A library for defining and expanding templated functions
About Type-Templates
This library allows you to define types and "template functions" that can be expanded into various type-specialised versions to eliminate runtime dispatch overhead. It was specifically designed to implement low-level numerical data types and functionality.
How To
First, let's define a meta-type that can instantiate structure types. For an example, let's implement 3-dimensional vectors, which can hold different element types.
(define-template-type vec (element-type)
(compose-name NIL element-type 'vec)
(field (compose-name NIL element-type 'vec '-x)
:type element-type :alias (:x))
(field (compose-name NIL element-type 'vec '-y)
:type element-type :alias (:y))
(field (compose-name NIL element-type 'vec '-z)
:type element-type :alias (:z)))
This creates a vec-type
meta-type that describes how a vec
type is created. Now let's instantiate it:
(define-vec single-float)
(define-vec double-float)
(define-vec fixnum)
We should now have the structure types single-float-vec
, double-float-vec
, and fixnum-vec
, each with their own field accessors and direct constructors. To present an easier way for users to access the x
, y
and z
slots of the vectors, let's create a dispatch function that'll call the specific slot accessor depending on the argument type.
(define-type-dispatch x (vec)
((single-float-vec) single-float (single-float-vec-x vec))
((double-float-vec) double-float (double-float-vec-x vec))
((fixnum-vec) fixnum (fixnum-vec-x vec)))
This will create a function x
as well as internal compiler structures to eliminate the runtime dispatch if the types are known ahead. However, you may notice that manually listing the cases like this is rather tedious. Let's create a macro to emit the type dispatcher cases for us.
(defmacro define-slot-reader (slot)
`(define-type-dispatch ,slot (vec)
,@(loop for type in (instances 'vec-type)
collect `((,(lisp-type type)) ,(place-type type slot)
,(place-form type slot 'vec)))))
This macro goes through all type instances of our meta-type and emits a dispatch matching that type, with the slot's value type as the return type, and the reader form for the vec
variable to read out the actual value. If you expand (define-slot-reader x)
you should get the same as we manually wrote above.
Because defining a slot dispatcher is such a common problem, you can also just use define-slot-accessor
, which will also take care of defining the corresponding writer function.
(define-slot-accessor vec-type x x)
You can see now how this library allows you to reason about structure types and automatically compute a lot more information. To illustrate this even better, let's define a template function that'll implement the dot product.
(define-template dot element-type (a b)
(let ((type (type-instance 'vec-type element-type)))
`((declare (type ,(lisp-type type) a b)
(return-type ,element-type)
inline)
(+ ,@(loop for slot in (slots type)
collect `(* ,(place-form type slot a) ,(place-form type slot b)))))))
Here we make use of the slot iteration, so conceivably the number of slots could also be made variable between vec-type
instances, and this template would still operate correctly.
Also notable are that the additional declarations: return-type
lets you specify the return type of the resulting function the template generates, and inline
lets you specify that the function should be declared inline.
To now instantiate the template into actual function definitions, we could simply repeat define-dot
for every element type we have, or we could do it like this:
(do-type-combinations vec-type define-dot)
This will expand into a call to define-dot
for all template arguments that were used to instantiate a vec-type
. The names of the functions will follow the scheme of dot/single-float
, dot/double-float
, etc.
We'll now again want to define a dispatcher function as an easy entry point for the user. For template-defined functions however we can make use of another shorthand:
(define-templated-dispatch dot (a b)
((vec-type 0) dot))
The templated dispatch macro will notice the meta-type, and automatically expand it into all concrete type instances, appending the template arguments to the template name to reach the correct specific version of the template. The 0
here means that the second argument type should be the same as the first, meaning only (single-float-vec single-float-vec)
, etc. will get a branch, but not (single-float-vec fixnum-vec)
.
With this you should have a broad overview of how to use the template system. Please refer to the individual functions used in the tutorial for further information on their capabilities.
System Information
Definition Index
-
ORG.SHIRAKUMO.TYPE-TEMPLATES
No documentation provided.-
EXTERNAL CLASS SLOT
Represents the metadata of a slot on a template type. See TEMPLATE-TYPE See NAMES See ACCESSOR See LISP-TYPE See VALUE See READ-ONLY See COMPUTED See REALIZED-SLOT-P
-
EXTERNAL CLASS TEMPLATE-TYPE
Represents an instantiable type definition. See LISP-TYPE See PARENT See CONSTRUCTOR See SLOTS See INSTANCES See TYPE-INSTANCE See SLOT See PLACE See PLACE-FORM See PLACE-TYPE See TEMPLATE-ARGUMENTS See DEFINE-TEMPLATE-TYPE See DEFINE-TYPE-INSTANCE
-
EXTERNAL CLASS TYPE-ALIAS
Representation of an alias of another template-type. See TEMPLATE-TYPE (type) See DEFINE-TYPE-ALIAS
-
EXTERNAL CONDITION NO-SUCH-INSTANCE
Error signalled when trying to fetch a type instance that does not exist. See TEMPLATE-TYPE (type)
-
EXTERNAL CONDITION NO-SUCH-SLOT
Error signalled when trying to fetch a slot that does not exist. See SLOT
-
EXTERNAL CONDITION NOT-A-TEMPLATE-TYPE
Error signalled when trying to coerce a type that does not name a template-type. See TEMPLATE-TYPE (type)
-
EXTERNAL CONDITION TEMPLATE-UNFULFILLABLE
Error signalled to notify that the template cannot be expanded for the given arguments. This is also available as a local function of the same name within DEFINE-TEMPLATE, to allow you to easily signal the condition. See DEFINE-TEMPLATE
-
EXTERNAL STRUCTURE TYPE-OBJECT
Supertype for all structures derived from template-types. See TEMPLATE-TYPE (type) See TEMPLATE-TYPE See TYPE-INSTANCE See TEMPLATE-ARGUMENTS
-
EXTERNAL FUNCTION COMPOSE-NAME
- SEPARATOR
- &REST
- PARTS
Compose a symbol out of parts. The symbol will be interned in the current package. Separator should be a string designator that will be injected between each part. Each part otherwise is added to the symbol name via PRINC-TO-STRING. See CL:*PACKAGE* See FORMAT-NAME
-
EXTERNAL FUNCTION ENUMERATE-COMBINATIONS
- &REST
- COMBINATIONS
Returns a list of all possible permutations of the given sets of items. Eg: (enumerate-combinations '(a b) '(1 2)) => ((a 1) (a 2) (b 1) (b 2))
-
EXTERNAL FUNCTION FORMAT-NAME
- FORMAT
- &REST
- ARGS
Format a new symbol. The symbol will be interned in the current package. The name is case-shuffled to the current readtable case after formatting. See CL:*PACKAGE* See CL:FORMAT See COMPOSE-NAME
-
EXTERNAL FUNCTION REALIZED-SLOT-P
- SLOT
Returns true if the slot is realised on the structure and holds a value, and isn't constant. See SLOT (type)
-
EXTERNAL GENERIC-FUNCTION ACCESSOR
- OBJECT
Returns the name of the accessor function for the slot. See SLOT (type)
-
EXTERNAL GENERIC-FUNCTION COMPUTE-SLOTS
- TEMPLATE-TYPE
Returns a list of all SLOT instances for the type instance. This returns all slots, including inherited ones. See SLOT (type) See SLOTS See TEMPLATE-TYPE (type)
-
EXTERNAL GENERIC-FUNCTION COMPUTE-TYPE-INSTANCE-DEFINITION
- TEMPLATE-TYPE
Computes the form used to define a type instance of the template type. Users may add methods to this that include the results of CALL-NEXT-METHOD in their return value, in order to append extra definitions, such as for PRINT-OBJECT. See TEMPLATE-TYPE (type)
-
EXTERNAL GENERIC-FUNCTION CONSTRUCTOR
- TEMPLATE-TYPE
Returns the name of the constructor function for the type instance. See TEMPLATE-TYPE (type)
-
EXTERNAL GENERIC-FUNCTION DIRECT-SLOTS
- TEMPLATE-TYPE
Returns the list of SLOT instances for the type instance. This only returns slots that were defined directly for this instance, excluding inherited slots. See SLOT (type) See SLOTS See TEMPLATE-TYPE (type)
-
EXTERNAL GENERIC-FUNCTION INSTANCES
- TEMPLATE-TYPE
Returns a list of all instances of the template type. See TEMPLATE-TYPE (type)
-
EXTERNAL GENERIC-FUNCTION (SETF INSTANCES)
- NEW-VALUE
- OBJECT
No documentation provided. -
EXTERNAL GENERIC-FUNCTION LISP-TYPE
- TEMPLATE-TYPE
Returns the name of the lisp-type for the type instance. See TEMPLATE-TYPE (type)
-
EXTERNAL GENERIC-FUNCTION NAMES
- OBJECT
Returns the list of alternate names for the slot. See SLOT (type)
-
EXTERNAL GENERIC-FUNCTION PLACE
- TEMPLATE-TYPE
- QUALIFIER
Returns the name of the place for the given slot. QUALIFIER can either be a SLOT instance or the name of a slot on the TEMPLATE-TYPE. See SLOT See PLACE-FORM See TEMPLATE-TYPE (type)
-
EXTERNAL GENERIC-FUNCTION PLACE-FORM
- TEMPLATE-TYPE
- QUALIFIER
- VAR
Returns an accessor form of the place for the given slot. This form can be used to read or SETF the value off the slot on the instance bound to the symbol passed in VAR. See SLOT See PLACE See TEMPLATE-TYPE (type)
-
EXTERNAL GENERIC-FUNCTION PLACE-TYPE
- TEMPLATE-TYPE
- QUALIFIER
Returns the lisp-type of the value stored in the slot. See SLOT See PLACE See TEMPLATE-TYPE (type)
-
EXTERNAL GENERIC-FUNCTION READ-ONLY
- OBJECT
Returns true if the slot can only be read, but not set. See SLOT (type)
-
EXTERNAL GENERIC-FUNCTION SLOT
- TEMPLATE-TYPE
- QUALIFIER
Find a slot with the given qualifier on the type instance. If the slot does not exist, an error of type NO-SUCH-SLOT is signalled. See NO-SUCH-SLOT (type) See SLOT (type) See TEMPLATE-TYPE (type)
-
EXTERNAL GENERIC-FUNCTION SLOTS
- TEMPLATE-TYPE
Returns the list of SLOT instances for the type instance. This returns all slots, including inherited ones. See SLOT (type) See DIRECT-SLOTS See TEMPLATE-TYPE (type)
-
EXTERNAL GENERIC-FUNCTION TEMPLATE-ARGUMENTS
- TEMPLATE-TYPE
Returns the arguments of the template instance or template type. See TEMPLATE-TYPE (type)
-
EXTERNAL GENERIC-FUNCTION TEMPLATE-TYPE
- TYPE
Returns the TEMPLATE-TYPE named by the given symbol. See TEMPLATE-TYPE (type)
-
EXTERNAL GENERIC-FUNCTION TYPE-INSTANCE
- BASE-TYPE
- &REST
- TEMPLATE-ARGS
Returns an instance of the given template type that fulfils the given template arguments. If no such instance exists, an error of type NO-SUCH-INSTANCE is signalled. See NO-SUCH-INSTANCE See TEMPLATE-TYPE (type)
-
EXTERNAL GENERIC-FUNCTION VALUE
- OBJECT
Returns the constant value form for the slot. If the slot is realised and does not have a constant value, an error is signalled. See SLOT (type) See REALIZED-SLOT-P
-
EXTERNAL MACRO DEFINE-ALIAS
- FUN
- ARGS
- &BODY
- EXPANSION
Define a simple alias function. EXPANSION should evaluate to a form that is used in the function body. This is similar to defining a compiler-macro, except that it tries to automatically define both a compiler macro and a regular function definition at once.
-
EXTERNAL MACRO DEFINE-DEPENDENT-DISPATCH-TYPE
- NAME
- TYPE-LIST
- I
- &REST
- ARGS
- &BODY
- BODY
Defines a function that can be used to compute more complex dependent types in templated dispatch function definitions. TYPE-LIST is bound to the list of ARGTYPEs in the expansion. I is bound to the index of the current dependent dispatch type to expand. ARGS are bound to the respective arguments of the call. BODY should return a concrete type to use in place of the dependent type expression, or NIL if there is no dependent type and the expansion should be eliminated. See DEFINE-TEMPLATED-DISPATCH
-
EXTERNAL MACRO DEFINE-SLOT-ACCESSOR
- TEMPLATE-TYPE
- NAME
- SLOT
Shorthand to define a dispatcher for an accessor of a given slot of a template type. See DEFINE-TYPE-DISPATCH See TEMPLATE-TYPE (type) See INSTANCES See SLOT
-
EXTERNAL MACRO DEFINE-TEMPLATE
- NAME
- &REST
- ARGS
Define a new template function. NAME will be used as the prefix for all emitted template instances. NAME will be concatenated together with DEFINE- to name the macro that is used to emit template instances. The structure of a DEFINE-TEMPLATE use should be as follows: (define-template NAME TEMPLATE-ARGUMENT+ INSTANCE-LAMBDA-LIST BODY*) TEMPLATE-ARGUMENTS should be symbols naming the variables bound to the template arguments during BODY. INSTANCE-LAMBDA-LIST should be the lambda-list of an emitted function instance. BODY should be any number of forms which return a list of body forms to emit into the resulting function instance. The first of those forms may be a DECLARE expression, with the following special declarations: TYPE --- Used to declare types of the function instance's arguments. Together with the RETURN-TYPE these will be used to create an FTYPE declaration for the function instance. RETURN-TYPE --- The function instance will declare this as the type of the return value. INLINE --- The function instance will be declared inline The resulting definition macro will take the template arguments as arguments as well as an optional name for the resulting function instance. If no name is given, the name is automatically composed out off the template name and the template arguments, separated by a slash. A local function is bound during evaluation of BODY named TEMPLATE-UNFULFILLABLE. When called, a TEMPLATE-UNFULFILLABLE error is signalled to signify that the given template arguments are not a valid combination. See COMPOSE-NAME See DEFINE-TEMPLATED-DISPATCH
-
EXTERNAL MACRO DEFINE-TEMPLATE-TYPE
- NAME
- TEMPLATE-ARGS
- NAME-CONSTRUCTOR
- &BODY
- BODY
Define a new template type. NAME will be concatenated together with -TYPE and interned into the local package to produce the name of the template type. NAME will also be concatenated together with DEFINE- to name a macro used to define instances of the template type. TEMPLATE-ARGS should be a list of arguments the template accepts. NAME-CONSTRUCTOR should be a form that, when evaluated, returns a symbol naming the type instance for the given template arguments. BODY may accept the following keyword arguments: :INCLUDE --- Specify another template-type to use as the supertype. This is done via a list that should be composed out of the template-type name and the template arguments to supply for that supertype. You may use the name of local template arguments. The rest of the BODY should be a number of forms. The forms are evaluated in an environment where the FIELD function is bound and should use it to emit information about the slots on the resulting type instance. See FIELD See TEMPLATE-TYPE (type) See DEFINE-TYPE-INSTANCE
-
EXTERNAL MACRO DEFINE-TEMPLATED-DISPATCH
- NAME
- ARGS
- &BODY
- BODY
Define a dispatcher function using type template information. BODY accepts the following keyword arguments: :IGNORE-TEMPLATE-TYPES --- A list of template type names that should be ignored for the resulting template invocation's template arguments. The rest of the body should have the following structure: EXPANSIONS ::= EXPANSION* EXPANSION ::= ((ARGTYPE*) TEMPLATE TEMPLATE-ARG*) | ((ARGTYPE*) (TEMPLATE TEMPLATE-ARG*) ARG*) ARGTYPE ::= TEMPLATE-TYPE | REFERENCE | DEPENDENT | REF-ARGUMENT TEMPLATE-TYPE --- The name of a template-type, for each of the instances of which this expansion will be instantiated. REFERENCE --- A number duplicating the concrete type at that position of the ARGTYPE list. DEPENDENT ::= #'(DEPENDENT-NAME ARG*) ALIAS-NAME --- The name of a dependent dispatch type function. REF-ARGUMENT --- A vector of two elements, the first being the position of the template type instance to reference in the ARGTYPE list, and the second being the number of the template argument of that template type instance to use. TEMPLATE --- The name of the template to call. TEMPLATE-ARG --- Additional template arguments that will be prepended before the combined template arguments of the TEMPLATE-TYPE instance expanded for this EXPANSION. Note that this includes *all* template arguments of all template-type instances in the ARGTYPES list that aren't excluded via the IGNORE-TEMPLATE-TYPES option above. ARG --- An argument to pass to the function call. The effective function call will be computed based on the template name and the template arguments, inserting a slash between each as per the standard naming convention. See DEFINE-TEMPLATE See DEFINE-TYPE-DISPATCH See DEFINE-DEPENDENT-DISPATCH-TYPE See TEMPLATE-TYPE (type)
-
EXTERNAL MACRO DEFINE-TYPE-ALIAS
- NAME
- &REST
- TYPES
Define an alias for a number of template type instances. NAME will name a lisp-type of NAME. NAME will also be concatenated together with -TYPE to name a TEMPLATE-TYPE that holds the type instances. See TYPE-ALIAS
-
EXTERNAL MACRO DEFINE-TYPE-DISPATCH
- NAME
- ARGS
- &BODY
- EXPANSIONS
Define a dispatcher function. EXPANSIONS should have the following structure: EXPANSIONS ::= EXPANSION* EXPANSION ::= ((ARGTYPE*) RETTYPE EXPANSION) ARGTYPE --- A lisp-type for the corresponding lambda-list variable. If the number of argtypes is shorter than the number of variables in the lambda-list, the remainder are automatically bound to NULL. RETTYPE --- A lisp-type for the type of the value returned in this expansion. EXPANSION --- A form that the type dispatcher will expand into should this branch of argument types match. See DEFINE-TEMPLATED-DISPATCH
-
EXTERNAL MACRO DEFINE-TYPE-INSTANCE
- TEMPLATE-TYPE
- NAME
- &BODY
- ARGS
Define an instance of a template type using the specified name and template arguments. See COMPUTE-TYPE-INSTANCE-DEFINITION See TEMPLATE-TYPE (type)
-
EXTERNAL MACRO DEFINE-TYPE-WITH-CONVERTER
- NAME
- BASE-TYPE
- VALUE
- &BODY
- CONVERSION
Define an alias for a longer lisp type with a conversion function to coerce values to fit within that type. BASE-TYPE should be the type this is an alias for, and CONVERSION the body of the function used to coerce any value to the requested type.
-
EXTERNAL MACRO DO-COMBINATIONS
- TEMPLATE
- &REST
- ARGUMENT-COMBINATIONS
Expand all possible combinations of arguments into forms. This will try to expand into all permutations off template arguments for the given template-type for which the template does not signal a TEMPLATE-UNFULFILLABLE error. See DEFINE-TEMPLATE See TEMPLATE-UNFULFILLABLE See ENUMERATE-COMBINATIONS
-
EXTERNAL MACRO DO-INSTANCE-COMBINATIONS
- TEMPLATE
- &REST
- TYPE-TEMPLATES
Expand all lisp-type names for instances of the given template-types. This is useful if the template accepts type instance names for template-arguments. See TEMPLATE-TYPE (type) See DO-COMBINATIONS
-
EXTERNAL MACRO DO-TYPE-COMBINATIONS
- TYPE
- TEMPLATE
- &REST
- OTHER-TEMPLATE-ARGS
Expand all possible type arguments for instances of the given template-type. OTHER-TEMPLATE-ARGS can be further permutation lists that precede the arguments of the template type instances. This is useful if the template accepts the same template arguments as the template type. See TEMPLATE-TYPE (type) See DO-COMBINATIONS
-