nl provides a primitive verb, Exists, that we extend to define other verbs. So, to define our verbs, the first thing we need to do is to import Exists from nl:
>>> from nl import Exists
Defining verbs, like defining nouns, affects the knowledge base, through the metaclasss of Exists, i.e. Verb:
>>> from nl import Verb
>>> type(Exists) is Verb
True
The definition of verbs is a little more complex than the definition of common nouns. There are 2 class attributes we may want to define for our verbs (both are optional). These attributes set limits to the subjects of facts in which instances of our verbs take part (as predicates), and to the modifiers that they can take.
- The first attribute is subject. This is assigned to a Noun, i.e., to Thing or to a class derived from it. So, for example, if we define a verb Loves and give it as subject HumanBeing, any fact that has Loves as a verb in its predicate, must have a HumanBeing instance as subject. If we don’t set the subject of a verb, it will default to Thing, so the subject in a fact with that verb could be anything.
- Second, we define the modifiers that the verb can take when used in a predicate. To do this, we assign a dictionary to a mods attribute on the class. The keys of this dictionary must be strings, and will correspond to the names of those modifiers (so they also have to be legal Python_ names). The values of this dictionary must be classes, so that the corresponding named modifiers of the verb in a predicate will be objects of that class. If the mods attribute is not given, it will default to an empty dictionary.
>>> class Loves(Exists): ... subject = HumanBeing ... mods = {'who': HumanBeing}
Now, we might instantiate Loves to produce a predicate:
>>> loves_mary = Loves(who=mary)
As is the case with things, this does not alter the knowledge base. And, contrary to the case with things, in the normal use of nl we do not tell predicates. We use predicates to build facts, which are then entered into the knowledge base through tell. There is no theoretical or technical reason for that, it is simply not implemented because I don’t see any practical use for it.
A verb can have more than one item in the mods dictionary. For example, we might have defined a noun “amount” and given a few objects of the class, and we might have given an item “how_much” to the mods dictionary of Loves:
>>> class Amount(Thing): pass
>>> a_lot = Amount('a_lot')
>>> a_little = Amount('a_little')
>>> very_little = Amount('very_little')
>>> kb.tell(a_lot, a_little, very_little)
>>> class Loves2(Exists):
... subject = HumanBeing
... mods = {'who': HumanBeing,
... 'how_much': Amount}
Then, we might have a predicate like:
>>> loves_mary_a_lot = Loves2(who=mary, how_much=a_lot)
However, we do not have to provide all the modifiers suggested in the definition of the verb, and might also have predicates like:
>>> loves2_mary = Loves2(who=mary)
>>> loves_a_lot = Loves2(how_much=a_lot)
As is also the case with things, we are not forced to extend Exists directly, and can extend from any other verb, so we might have:
>>> class Loves3(Loves):
... mods = {'how_much': Amount}
In this case, we would have a verb, Loves3, that has virtually the same form as Loves2, and with it we might build predicates exactly with the same form as the above loves2_anne or loves_a_lot. Thus, the modifiers that we may give to a verb to produce a predicate are not just given by the mods dictionary of its class, but by the union of all the mods dictionaries of its class, and all classes in its class’ mro.
In the previous sections we have defined verbs that have, as modifiers, Thing instances. We do not have to limit ourselves to this kind of objects, though. We can, for example, have a verb with a modifier that extends Exists, so that the predicates that instantiate it have other predicates as modifiers. For example:
>>> class Wants(Exists):
... subject = HumanBeing
... mods = {'what': Exists}
With this Wants verb, we might build predicates such as:
>>> wants_to_luv_mary = Wants(what=Loves(who=mary))
Another important class of modifier we may provide a verb with are numbers. Instead of the rather absurd Amount class we defined earlier, we might have imported Number from nl, and provided it as value for the key 'how_much'. For example:
>>> from nl import Number
>>> class Runs(Exists):
... subject = HumanBeing
... mods = {'v': Number}
>>> r1 = Runs(v=1)
or, also, more inconveniently:
>>> r2 = Runs(v=Number(2))
To finish this section, we will add that we can also provide Verb or Noun as values in the mods dictionary of a verb definition, so that in predicates, the modifiers of such verbs will be actual subclasses of Thing or Exists rather than instances of them.
I will defer giving examples of this feature until a later section, in which I will provide a complete “real world example” of the usage of nl.