DefineLink

From OpenCog
Jump to: navigation, search

The DefineLink is used to give a unique name to an atom (a pattern, a function, a type, etc). When it a defined name is encountered during pattern matching, or during evaluation/execution, it is replaced by the the definition. It was added to atomese to make it easier for human coders, who are hand-writing atomese, to create human-readable, structured code. As such, it is not really central to atomese, and is best avoided, unless you really do need it for some purpose. For knowledge-representation tasks, it is suggested that the EquivalenceLink be used instead; it is better suited for associating declarative facts. DefineLink can be thought of as the imperative form of the EquivalenceLink. See the link comparison chart for other such correspondences.

The DefineLink is vaguely similar to 'define' in scheme, but also sharply different in that it is not scoped, and also, it is not mutable. Many users might benefit from using the StateLink instead of DefineLink.

There are three things that one may typically want to "define":

  • (a) associate a name to some hypergraph, typically, a pattern, so that the named object can be used with the pattern matcher.
  • (b) define a new link type, and, specifically, an imperative link type, so that executing the imperative link causes the same action to be performed as it's definition. You actually define a DefinedSchemaNode as you need a name for the new 'link'.

The DefineLink does NOT bind any variables inside of it; these remain free. Thus, DefineLink can be used when creating more complex structures containing common (shared) variables between them. To bind variables, use the LambdaLink or the FunctionLink, as shown in the DefinedSchemaNode example, below.

DefineLink is similar to StateLink, which also allows only one definition at a time; the difference being that DefineLink will throw an error if a second definition is attempted, whereas the StateLink will automatically delete the old definition.

DefineLink inherits from UniqueLink, which provides the actual mechanics implementing uniqueness.

Structure

DefineLink
   <Name>
   <Definition>

At this time, the type of <Name> is only allowed to be DefinedPredicateNode, DefinedSchemaNode or DefinedTypeNode. It is not valid to use DefineLink with any other types!

Note that in spite of this limitation one can use DefineLink such that the Definition is any atom type, by considering DefinedSchemaNode as a nullary schema defining a constant. In that case there is no need to use ExecutionOutputLink to get the constant out of a DefinedSchemaNode, the DefinedSchemaNode is the constant itself. See here for an example.

Uniqueness of name

Given for instance

DefineLink
   DefinedPredicateNode "NewName"
   PredicateNode "My predicate"

the following

DefineLink
   DefinedPredicateNode "NewName"
   PredicateNode "My other predicate"

would not be permitted because the DefinedPreidcateNode "NewName" has already a definition, the PedicateNode "My predicate".

C++ API

The C++ DefineLink class offers the get_definition() method to get the definition associated to a DefineLink.

Examples

DefinedPredicateNode

The following uses DefineLink to define a DefinedPredicateNode

DefineLink
   DefinedPredicateNode "MyPredicate"
   AndLink
      ...


The body of the AndLink should be any collection of atoms that, when evaluated, can be And'ed together. In place of the AndLink, one could use any TV-valued atom, such as OrLink, NotLink, AbsentLink, and so-on.

During pattern matching, when a "bare" DefinedPredicateNode is encountered, it will be checked to see if it has a definition. If it does, then it will be expanded, and the definition will be used in it's stead.

DefinedSchemaNode

One may use a DefineLink to define a DefinedSchemaNode. Note that DefineLink itself does not bind any variables; thus, a FunctionLink (a special case of LambdaLink) is used to perform the desired variable binding. For example:

DefineLink
   DefinedSchemaNode "x+y*10"
   LambdaLink
      VariableList
         VariableNode "$X"
         VariableNode "$Y"
      PlusLink
         VariableNode "$X"
         TimesLink
            VariableNode "$Y"
            NumberNode 10

One could then use this definition to execute "x+y*10"

ExecutionOutputLink
   DefinedSchemaNode "x+y*10"
   ListLink
      NumberNode 2
      NumberNode 4

by using cog-execute! The following works today:

(cog-execute! (ExecutionOutputLink
                  (DefinedSchemaNode "x+y*10")
                  (ListLink
                      (NumberNode "2")
                      (NumberNode "4")))

Running this returns

(NumberNode 42)

(explicitly tested in /tests/scm/SCMExecutionOutputUTest.cxxtest)

DefinedSchemaNode as constant

One may use DefinedSchemaNode to define a nullary schema (that is a constant) as well.

DefineLink
   DefinedSchemaNode "MyList"
   ListLink
      NumberNode "2"
      NumberNode "4"

And use the DefinedSchemaNode directly in place of the ListLink such as

(cog-execute! (ExecutionOutputLink
                  (DefinedSchemaNode "x+y*10")
                  (DefinedSchemaNode "MyList")))

which should return (TODO: not tested yet)

(NumberNode 42)

See Also