User-defined Types and Default Values in the Frame Syntax
Inheritable Types
In Ergo, the user can specify the types of the properties and methods in a class and have them inherited by every subclass and member-object of the class. These types are specified using two syntactic elements that resemble the syntax of the frames, which we discussed in The Basics: Facts, Rules, and Queries:
=>
instead of->
[|...|]
instead of[...]
For example: we write:
Person[|name=>\string, dateOfBirth=>\date, child=>Person|].
to state that, in class Person
, the type of the property 'name'
is \string
, the type of the property 'dateOfBirth'
is \date
, and that the property 'child'
has the type Person
. The class Person
is called the domain of each of the above three properties; the classes \string, \date
, and Person
are the ranges of the aforesaid properties name, dateOfBirth
, and child
, respectively.
Note that =>
is used to specify types, while ->
is for specifying values
(cf. Person[|name=>\string|
] vs. john123[name -> 'John Doe']
).
Suppose now that Man is a subclass of Person, i.e., that the fact
Man::Person.
is inserted or derived. Then the following can also be derived:
Man[|name=>\string, dateOfBirth=>\date, child=>Person|].
I.e., the type information of our three properties is inherited by the subclass. Furthermore, suppose that John
is an instance (i.e., a member-object) of the class Man
, i.e., the fact
John:Man
.
is asserted or derived. Then the following can also be derived:
John[name=>\string, dateOfBirth=>\date, child=>Person].
I.e., the type information for our three properties is inherited by the individual object John
, an instance of the class Man
.
Note that the last statement uses the plain brackets [...]
instead of [|...|]
-- this is not a typo! In both cases, the symbol => is used to specify types, but the brackets are different.
Plain brackets [...]
are used to make statements about objects as such. Even if the object is actually a class that contains members, such statements do not apply to the members (or subclasses). Such properties are called non-inheritable. For example, average age (avgAge
, below) in class Person
should not be applicable to individual people, so should be specified as non-inheritable rather than as inheritable.
In contrast, [|...|]
are statements about classes that are inherited to the members and subclasses.
To summarize, suppose the knowledge base contains:
Person[|name=>\string, dateOfBirth=>\date, child=>Person|]. // inheritable
Person[avgAge=>\float]. // non-inheritable
Man::Person.
John:Man.
Then the following queries would yield the answer Yes (true):
Man[|name=>\string, dateOfBirth=>\date, child=>Person|].
John[name=>\string, dateOfBirth=>\date, child=>Person].
and the following queries will return No (false):
Man[avgAge=>?].
Because avgAge
is not inheritable. Even though conceptually avgAge
could make sense as a property of class Man
, the fact that it is defined for Person
(as a non-inheritable property) does not imply that this property is defined for the subclasses of Person
. We made avgAge
into a non-inheritable property because we don't want it to be inherited to the individual members of Person
, like John
. If we wanted to state that avgAge
applies to all subclasses of Person
, but not to the members of Person
, we would have used a rule:
Person[avgAge=>\float].
?C[avgAge=>\float] :- ?C::Person.
Note: the last rule shows that type specifications can be defined by rules, not just by facts.
John[avgAge=>?].
Because avgAge
is not inheritable.
Person[name=>\string, dateOfBirth=>\date, child=>Person].
Because name, dateOfBirth, child
are defined as properties of Person
as a class (i.e., inheritable, using [|...|])
, not as an object (i.e., non-inheritable, using [...]
).
Man[name=>\string, dateOfBirth=>\date, child=>Person].
Ditto.
John[|name=>\string, dateOfBirth=>\date, child=>Person|].
name, dateOfBirth, child
are properties of Person
that apply to individual objects as such, not as classes. This is why John[name=>\string, dateOfBirth=>\date, child=>Person]
is true while John[|name=>\string, dateOfBirth=>\date, child=>Person|]
is not.
Method arguments can also be typed. For instance:
Person[|currentAge(\date)=>\integer|].
Finally, we remark that, like frame properties, types don't need to be specified all at once. The following are equivalent:
Person[|name=>\string, dateOfBirth=>\date, child=>Person, currentAge(\date)=>\integer|].
and
Person[|name=>\string, dateOfBirth=>\date|].
Person[|child=>Person|].
Person[|currentAge(\date)=>\integer|].
or in any other combination of facts.
Non-inheritable Types
As we have seen, these are the types that apply to objects as such, not in their role as classes. These types are specified using
[...]
=>
Useful rules of thumb:
- Both inheritable and non-inheritable types can be
- specified directly as facts
- or defined by rules.
- Inheritable types are inherited to
- subclasses as inheritable types
- individual members of classes as non-inheritable types
- Types are inherited cumulatively. For instance:
AmphibiousCar::Car. // the class of amphibious cars is a subclass of the class of cars
// (i.e., every object of class AmphibiousCar is also an object of class Car)
AmphibiousCar::Boat. // ... and also of the class of boats
amphicar:AmphibiousCar. // amphicar is an object that belongs to the class of amphibious cars
Car[|category=>LandVehicle|].
Boat[|category=>WaterCraft|].
From this, Ergo will derive
AmphibiousCar[|category=>{LandVehicle,WaterCraft}|]
as well as
amphicar[category=>{LandVehicle,WaterCraft}].
What are Types Good For?
Types are typically used for:
- specifying ontologies
- type checking
- documentation
Ontologies: these are normally statements about classes and their relationship to each other. The use of the => arrow provides benefits like inheritance and is typically the preferred way of specifying ontologies.
Type checking: one of the Ergo builtin libraries provides methods for verifying that object properties comply with the types specified for them. See the section on Type Checking in ErgoAI Reasoner User's Manual. This issue is also treated at the introductory level in the Capturing Real World Knowledge tutorial, in the section on Elements of advanced testing.
Documentation: by documenting the types of the class properties you are providing a lasting record that will facilitate future maintenance of the knowledge base and may help avoid costly mistakes.
Default Values
These are specified using
->
[|...|]
Default property values are to the ordinary values of the frame properties as inherited types are to non-inheritable types. In other words, default values are associated with (a.k.a., attached to) classes and are statements about class members (and subclasses) rather than about the classes to which they are attached. For instance:
Bird[|fly->yes|].
Seagull::Bird.
Fred:Seagull.
From this Ergo will derive by inheritance:
Seagull[|fly->yes|].
Fred[fly->yes].
Note that ->
is used to specify values both for individual objects (via the [...]
type of brackets, e.g., john123[name -> 'Mary Doe'])
and for default values of classes, as in the case of the classes Seagull
and Bird
above. The latter is done using the [|...|]
type of brackets.
Unlike type inheritance, the inheritance of default values can be overwritten both at the level of subclasses and at the level of individual objects. If, in addition, we have this information:
Ostrich[|fly->no|].
Tweety:Ostrich.
Willy:{Seagull,Sick}.
?X[fly->no] :- ?X:Sick.
then the following can be derived:
Tweety[fly->no].
Furthermore, neither Tweety[fly->yes]
nor Ostrich[|fly->yes|]
(nor Ostrich[fly->yes]
) are derived. This is because inheritance of Ostrich[|fly->yes|]
is overridden and because Ostrich
is a more specific class for Tweety
, it inherits fly->no
from Ostrich
rather than fly->yes
from Bird
.
Willy[fly->no].
Although Willy
is a Seagull
and is supposed to fly, Willy
is sick and sick entities do not fly according to the last rule. Since this is an explicit information given for Willy
, it overrides the inheritance of fly->yes
from Bird
.
Ergo supports multiple inheritance. Here are some useful rules of thumb about inheritance of default values:
- Default inheritance can be overridden by mode specific information.
- Multiple inheritance: different default properties can be inherited from incomparable classes (i.e., classes that are not subclasses of each other). If the same property inherits different default values from incomparable classes then the inherited values have the truth value undefined. For instance:
a:{b,c}.
b[|foo->1|].
c[|foo->2|].
then a[foo->1]
and a[foo->2]
are not true.
- Default properties are inherited to
- subclasses as inheritable default properties (i.e., as
[|...|]
). - class members as non-inheritable properties (i.e., as
[...]
).
- subclasses as inheritable default properties (i.e., as
- Default properties can be specified as facts as well as by rules. (We have already seen that regular properties can be specified in either of these ways, too.)