SignatureLink
A SignatureLink
is a type constructor -- it is used to declare a pattern type signature. A signature consists of type declarations, and is used to declare an algebraic data type. It can be used wherever a TypeNode can be used: for example, with the TypedVariableLink
(which is used inside of VariableList
, LambdaLink
and BindLink
) to specify complex variable types. It can also be used with the TypedAtomLink to indicate the type of some given atom. Signatures are used by type checking to enforce type restrictions.
Function type declarations can be created with the ArrowLink, which is a function type constructor.
The FilterLink proposal uses the SignatureLink to filter a set of atoms.
The deep types page discusses a similar idea.
The FuzzyLink is a link type, similar to a SignatureLink, but not requiring an exact match, but allowing only an approximate match. This can be used to perform fuzzy searching.
Contents
Examples
This is best illustrated by means of examples. Thus, for example, the following link:
ListLink ConceptNode "some" ConceptNode "thing"
has the signature
Signature ListLink Type "ConceptNode" Type "ConceptNode"
Conversely, the above signature only matches the structure of ListLinks that have exactly two members in their outgoing set, both of which are ConceptNodes.
A more complex example is the prototypical EvaluationLink, having the form
EvaluationLink PredicateNode "Some property" ListLink ConceptNode "thing A" ConceptNode "thing B"
This has the signature:
Signature EvaluationLink Type "PredicateNode" ListLink Type "ConceptNode" Type "ConceptNode"
Type constants
Signatures can include constants. In that sense, they resemble the patterns searched for by the pattern matcher. Thus,
EvaluationLink PredicateNode "Some property" ListLink ConceptNode "thing A" ConceptNode "thing B"
also has the signature
Signature EvaluationLink Type "PredicateNode" ListLink ConceptNode "thing A" Type "ConceptNode"
as well as the signature
Signature EvaluationLink PredicateNode "Some property" ListLink Type "ConceptNode" ConceptNode "thing B"
These signatures are narrower, in that they specify types that are more restrictive. Thus, the first signature above will match any EvaluationLink, with any PredicateNode, but it must explicitly have ConceptNode "thing A" within it. The second signature only matches those EvaluationLink's whose PredicateNode is "Some property". When a specific non-type atom appears in a SignatureLink, it can be thought of as a "type constant"; it is fixed, not variable. Thus PredicateNode "Some property" is a type constant in the last example.
Polymorphism
The TypeChoice link can be used to define polymorphic signatures. Thus, for example,
Signature EvaluationLink TypeChoice Type "PredicateNode" Type "GroundedPredicateNode" ListLink Type "ConceptNode" Type "ConceptNode"
is the combinanation of two signatures, one for the ordinary EvaluationLink, using an ordinary PredicateNode, and one using a GroundedPredicateNode. That is, it combines this signature:
Signature EvaluationLink Type "PredicateNode" ListLink Type "ConceptNode" Type "ConceptNode"
with this signature:
Signature EvaluationLink Type "GroundedPredicateNode" ListLink Type "ConceptNode" Type "ConceptNode"
Type checking
The pattern matcher can be used to perform type query and type checking. The current type-checker is fairly simple: it is implemented as the "value_is_type()" function; see /opencog/atomutils/TypeUtils.h At this time, it does not have a scheme wrapper, but it could.
To perform a type query, once simply search the entire atomspace for a given signature by employing the BindLink. Thus, for example, all atoms of the following signature
Signature EvaluationLink Type "PredicateNode" ListLink Type "ConceptNode" Type "ConceptNode"
can be obtained by performing the search
Get TypedVariable Variable "$x" Signature ... etc as above... Variable "$x"
The above query works today, although it is not optimized, and might run slow on a large atomspace. Its not hard to optimize, just no one has needed this yet.
You could do the same thing without using a SignatureLink, but it would much more verbose (although, currently, it would probably run faster). As follows:
Get VariableList TypedVariable Variable "$any-pred" Type "PredicateNode" TypedVariable Variable "$any-concept" Type "ConceptNode" TypedVariable Variable "$any-other-concept" Type "ConceptNode" EvaluationLink Variable "$any-pred" ListLink Variable "$any-concept" Variable "$any-other-concept"
Note that the GetLink is more verbose than the SignatureLink variant
Note that using the pattern matcher is overkill for basic type checking, such as that given above. That is because basic type checking is guaranteed to terminate in finite time: you just walk to the bottom of the tree.
Type equations
The pattern matcher becomes useful only if type equations are needed, for example:
SignatureLink EvaluationLink TypeNode "PredicateNode" ListLink TypeVar "$some-type" TypeVar "$some-type"
Here, the "TypeVar $some-type" implies that the two slots of the ListLink must be of the same type, whatever type that may be. Solving this kind of type equation would require the pattern matcher, and could not easily be done with basic tree code. (In other words, type equations are currently not supported).
Unit test
The /tests/query/DeepTypeUTest.cxxtest implements a unit test for this function. The /examples/pattern-matcher/type-signature.scm provides a demo.