API
Conditions
inference-errorcycle-detectednodeAn already seen nodeOption Value Allocation: instance Type: nilInitarg: :nodeReaders: (cycle-detected-node)
typesystem-errortype-systemA top node of the type systemOption Value Allocation: instance Type: nilInitarg: :type-systemReaders: (typesystem-error-system)
incorrect-definitionarity-erroractual-arityArity of a function seen in the codeOption Value Allocation: instance Type: alexandria:non-negative-fixnumInitarg: :actualReaders: (actual-arity)expected-arityArity of a function in FNDBOption Value Allocation: instance Type: alexandria:non-negative-fixnumInitarg: :expectedReaders: (expected-arity)
unknown-functionunknown-literalcodeAn expression which contains unknown literalOption Value Allocation: instance Type: nilInitarg: :codeReaders: (unknown-literal-code)
fndb-entry-existsparser-errorcodeParser errorOption Value Allocation: instance Type: nilInitarg: :codeReaders: (parser-error-code)
typecheck-errorvarnameName of the variable which holds a value of invalid typeOption Value Allocation: instance Type: nilInitarg: :varnameReaders: (typecheck-error-varname)actualActual type of a value stored in the variableOption Value Allocation: instance Type: nilInitarg: :actualReaders: (typecheck-error-actual)expectedExpected type of a value stored in the variableOption Value Allocation: instance Type: nilInitarg: :expectedInitform: nilReaders: (typecheck-error-expected)
cannot-redefineType system
During to serapeum limitations, the typetype-node and the
corresponding constructor cannot be documented. Look at examples in
this section.
type-node-ordernil:EQ, :LT, :GT or
NIL. The latter is to indicate that there is no order between two
types.le(order)t if order is either :eq or :lt, nil
otherwise.ge(order)t if order is either :eq or :gt, nil
otherwise.type-node-order(top t1 t2):eq when t1 = t2, :lt when t1 < t2, :gt
when t1 > t2 or nil otherwise. Top is the top type of the
type system.find-type-node(name type-node)A which has the name name and A ⊂
type-node.flatten-type-graph(type-node)type-node.check-type-system(type-node)type-node if a type system for which this node is a top
node is defined correctly, otherwise signal typesystem-error or
just do not return control.join(top t1 t2)t1 and t2. Join t is the
minimal type for which t1 ⊂ t and t2 ⊂ t. Top is the top
type for the type system.meet(top t1 t2)t1 and t2. Meet t is the
maximal type for which t ⊂ t1 and t ⊂ t2. Top is the top
type for the type system.types-intersect-p(top t1 t2)t if t1 ∧ t2 is not the bottom type, nil
otherwise. Top is the top type of the type system.print-graphviz-representation(top &optional (stream *standard-output*))top in
Graphviz format to the output stream stream.Known functions
defknown(db top names arguments-clause type-bindings-clause (&key (bottom-guard nil bottom-guard-p)) t0-cond-clauses &optional t1+-cond-clauses)Add new known functions to the database db. Top is the top
type of a type system. Names is a list of function names to be
added. The new functions all have the same arity and the same
functions \(T_0\), \(T_1\), etc.Arguments-clause is a form (arglist (result-variable
top-variable narg-variable)) and contains some important variables
which can be used in the body of functions \(T_i\). Arglist is a
list of variables which are bound to types of arguments of the defined
functions. Top-variable is bound to the top type of a type-system,
result-variable is bound to type of the result of the defined
function and narg-variable is bound to \(i-1\) in the body of
\(T_i\) when \(i > 0\).Type-bindings-clause is an associative list with entries in the
form (variable-name . type-name) which contains additional
bindings of variables to types inside \(T_i\) functions.Bottom-guard argument must always be present and be either nil
or name of a variable bound to the bottom type. If bottom-guard is
not null then bottom guards will be present in \(T_i\) functions.T0-cond-clauses define a body of function T₀ in which bindings to
top-variable and variables in arglist are in effect. This body
is an explicit cond, so t0-cond-clauses may be like this
((condition-1 form-1)
(condition-2 form-2)
etc)
T0-cond-clauses must evaluate to a type. If bottom-guard is
not nil an implicit conditional is inserted before all other
conditionals in cond. This conditional checks if any of variables in
arglist are bound to the bottom type, and if so the bottom type is
returned. Also another conditional is inserted after all other
conditionals which just returns the bottom type in any case.T1+-cond-clauses define a body of functions T₁, T₂, etc in which
bindings to top-variable, res-variable, narg-variable and
variables in arglist are in effect. This body is an explicit cond
and must evaluate to a type, just like T0-cond-clauses.
For example the following code
(defknown *fndb* *type-system* (length)((x)(res top n))
((integer . integer)
(sequence . sequence)
(bottom . nil))
(:bottom-guard bottom)
;; T₀
(((types-intersect-p top x sequence) integer))
;; T₁
(((ge (type-node-order top res integer))
(meet top x sequence))))
creates a function T₀
(lambda (top x)
(let ((integer (find-type-node 'integer top))
(sequence (find-type-node 'sequence top))
(bottom (find-type-node nil top)))
(cond
((eq x bottom) bottom)
((types-intersect-p top x sequence) integer)
(t bottom))))
and T₁
(lambda (top n res x)
(assert (< n 1))
(let ((integer (find-type-node 'integer top))
(sequence (find-type-node 'sequence top))
(bottom (find-type-node nil top)))
(cond
((or (eq x bottom)
(eq res bottom))
bottom)
((ge (type-node-order top res integer))
(meet top x sequence))
(t bottom))))
and adds a corresponding entry about the function length in
*fndb*.
defknown*(db top names arg-types res-type)names to the
function database fndb. This is a simplified SBCL-like version of
DEFKNOWN. Everything what is known about added functions is that
they take arguments of types arg-types and return a value of type
res-type.definitializer(db top name type)name which takes zero arguments
and returns a value of type type to FNDB db
(definitializer db top name type)
is equivalent to
(defknown db top (name)(() res top n)
((type-var . type))
(:bottom-guard nil)
((t type-var))
())
make-fndb(top-node)top-node.Code parsing
NB: This API is subject to change.parse-expr(code &optional literal-initializers)Parse an expression code and construct a control flow
graph. Literal-initializers is an associative list which contains
predicates as keys and initializer functions as values. When
parse-code sees a term of the expression, it runs predicates in
literal-initializers(in the order of appearance) on that term. If
a predicate returns T then that term is considered as a literal
and the corresponding initializer function is used to initialize a
constant variable with a value of type of the literal. For example:
CL-USER> (parse-code '(+ x 3)) ; => Signals UNKNOWN-LITERAL
CL-USER> (type-inference-engine:parse-expr
'(+ x 3)
(list
(cons #'integerp 'init/integer)))
((TYPE-INFERENCE-ENGINE:FLAT-CONTROL-NODE (2)(1)(#<TYPE-INFERENCE-ENGINE:STATEMENT X ← (INITIALIZE )>
#<TYPE-INFERENCE-ENGINE:STATEMENT RES567 ← (INITIALIZE )>
#<TYPE-INFERENCE-ENGINE:STATEMENT VAR568 ← (INITIALIZE )>))
(TYPE-INFERENCE-ENGINE:FLAT-CONTROL-NODE (0)(2)(#<TYPE-INFERENCE-ENGINE:STATEMENT VAR568 ← (INIT/INTEGER )>))
(TYPE-INFERENCE-ENGINE:FLAT-CONTROL-NODE (1)(0)(#<TYPE-INFERENCE-ENGINE:STATEMENT RES567 ← (+ X
#:VAR568)>)))
This function returns a control flow graph which can be passed to infer-types.
compile-function(form fndb top-type &optional literal-initializers)Infer types for a function defined by the defun form (just like in Common Lisp) and add this function to the database if it typechecks.
Example (tie/ex is a local nickname for the package
type-inference-engine/example):
TIE-EXAMPLE> (tie:compile-function
'(defun foo (x y)
(let ((z (elt x (1+ y))))
(* z (+ y z))))
tie/ex:*fndb* tie/ex:*type-system*)
#S(TIE::SIMPLE-KNOWN-FUNCTION
:NAME FOO
:ARG-TYPES (#<TIE:TYPE-NODE SEQUENCE {102E78D253}>
#<TIE:TYPE-NODE INTEGER {102E78D2B3}>)
:RES-TYPE #<TIE:TYPE-NODE NUMBER {102E78D313}>)
See also: parse-expr.
result-variable(flat-nodes)Type inference
infer-types(db top graph)parse-expr. Graph is an
internal representation of an expression in the form of parallel
assignment statements. Db is a database of known functions and
top is the top type of your type system. This function returns an
array of variable->type mappings for each parallel assignment
statement in the flattened control flow graph. The first element in
that array is the most important as it corresponds to a fully
evaluated expression.