Clone wiki

nl / Home



nl is a python library, that exposes a declarative API that allows us to build sentences and rules. These are used as input for a knowledge base built on the CLIPS production system. CLIPS builds a Rete network with the rules and sentences, which can then be queried for the consecuences of those in a most efficient way.

The main claim of nl is that its syntactic elements have the same form as their natural counterparts. This is not to say that nl's syntax is equivalent to the grammar of the natural language, nor even to say that the grammatical elements of the natural language have all a counterpart in nl. What is meant by that is simply that the syntax of nl has equivalent constructions in the natural language, and that the elements of nl can be used in nl's sentences just as the equivalent elements of the natural language would be used in the equivalent sentences. But, not that nl has equivalents to all contructions and elements of the natural language. I will try to offer an example of what is meant by this, analyzing the relationship between the natural language and OWL-DL. With OWL-DL, you can build triples, that are meant to correspond to sentences in the natural language made up of a subject, a verb, and an object. so, for example, for a natural sentence such as

johnny goes to hollywwod

in OWL-DL you would define a verb "goes_to", and names "john" and "hollywood", and would offer, as translation to the previous sentence (using n3 notation),

:Person a rdfs:Class. :Place a rdfs:Class. :johnny a :Person. :hollywood a :Place.

:goes_to a rdf:Property; rdfs:domain :Person; rdfs:range :Place.

:johnny :goes_to :hollywood.

However, with the natural language, you can use a predicate (verb + object) as the object in another predicate, and for example you can say something such as "johnny wants to go to hollywood". And that is something you cannot do with OWL-DL. So, OWL-DL's properties are supposed to be translatable to natural language verbs, but they cannot take all the syntactic positions that the natural verbs can take in the classes of natural sentences that have equivalent constructions in OWL-DL. With nl, however, you would have a translation of "johnny goes to hollywood" very similar to the one offered by OWL-DL, and you would also be able to use predications as objects in other predications, and have first order variables ranging over predications or classes, and generally mix and match proper names, verbs, predications, classes (common nouns), and variables (some, every) in the same way you would do it in the sentences of the natural language that have a formal counterpart in nl.

nl is based on a first-order theory, NL, a discussion of which can be found here. This discussion is probably required reading to understand the breadth and the limits of nl, but not to start using it.

There is a mailing list for nl.


For installation instructions, you can see the INSTALL.txt file in the distribution. Basically, just (with python2.5):

 $ easy_install nl


The API consists of a few classes, basically Thing , State , Fact , and Rule , and a few functions, basically, tell , extend and ask . Thing and State are subclassed to define, respectively, nouns and verbs, which are instantiated to build nominal and verb phrases, which in turn are used to instantiate Fact and Rule to build sentences. tell is used to enter these sentences into the system, extend is used to obtain all logical consecuences of a set of sentences, and ask is used to query the system.

A more elaborate example can be found in, combined with


Thing is subclassed to make what will be used like common nouns, e.g., "person". The derived classes are instantiated with a string [1] corresponding to a proper noun.

>>> from nl import Thing, State, Number, Fact, Rule, kb

>>> class Person(Thing):
...     pass

>>> john = Person('john')

>>> kb.tell(john)

These instances can be used in two ways. They can be passed directly to tell , and that will be like asserting a copular sentence, "John is a person". Once they have been added to the system in such a manner, they can also be used in facts, as subject or modifier in the predicate; more on this later.

[1] These strings have to be legal python names.


State is subclassed to make what will be used as verbs. (The word "state" is probably not a good choice to lend it's spelling to this class; it does not seem an ancestor of all verbs, and indeed, it is not a verb. "To be" might seem more approriate, but "to be" corresponds to predicates in NL, and, in nl, it is implied in the class structure: as we saw above, the fact that john is an instance of Man is interpreted as "john is a man".) And Verb is the name of State 's metaclass.

The subclasses of state are defined with a dictionary mods of strings to classes, which have to be subclasses of Thing, Noun, State, Verb , or Number (also from the nl namespace). Noun and Verb are the metaclasses of Thing and State. This mods dict represents the possible modifiers that the verb can have when instantiated as a predicate of ln. The subclasses of State can optionally take an attribute named subject , of class Thing .

>>> class Wants(State):
...     subject = Person
...     mods = {'what': State}

>>> class Content(Thing): pass

>>> class Publish(State):
...     subject = Person
...     mods = {'content': Content}

Classes derived from State are instantiated as verb phrases within facts, and are given, as **kwargs , a dictionary equivalent to the mods of the class, but with instances instead of classes, as we shall see in the next section.


Fact is instantiated to make facts, with three positional args representing subject, predicate, and (optional) time. As subject, it requires a Thing instance, as predicate a State instance, and as time, a Instant or Duration instance.

>>> class Document(Content): pass

>>> doc1 = Document('doc1')

>>> p1 = Fact( john, Wants( what=Publish( content=doc1 )))

>>> kb.tell(doc1, p1)

It can also take an additional named parameter truth of type boolean, that indicates whether the sentence is affirmed or denied, and defaults to True.


Rule is instantiated to build rules. The constuctor takes as positional arguments two lists of facts and things, to act as premises and as consecuences. What CLIPS will do with all this is to seek for instances (stand alone facts and things) that match the premises, and once it covers all the premises in a rule, adds the consecuences as stand-alone sentences.

Variables can be used within rules. They are given by a string composed by an upper case letter followed by digits. They can be used in any place where intances of Thing, State, Noun, Verb, or Number might be used. Their scope is the rule where they appear, and their only role is to match with names, when present in the premises, and to be substituted by the match when present in the consecuences.

>>> r1 = Rule([
...            Fact( Person('P1'), Wants( what=State('X1')))
...            ],[
...            Fact( Person('P1'), State('X1'))])

>>> kb.tell(r1)

extend and ask

Now, we can extend the database to all its logical consecuences. With the previous sentences, there is only one consecuence: that john publishes doc1:

>>> assert not kb.ask(Fact( john, Publish( content=doc1 ), 0 ))

>>> kb.extend()

>>> assert kb.ask(Fact( john, Publish( content=doc1 ), 0 ))


Modifiers in predicates can have a numeric value, specified in the verb definition as Number . In stand alone facts, numbers are just numbers, integers or floats. In a rule, they can be arithmetic operations in which variables take part. The syntax for these operations is (<op> <arg1> <arg2>) . At the moment, only binary operations are allowed. Of course, any of the arguments can itself be an operation. The operators can be any of the arithmetic operators allowed in clips.

Additionally, we can include arithmetic sentences, with truth value instead of numeric value, as premises in a rule. The allowed predicates are the arithmetic predicates allowed in clips, and the syntax is the same as that of operations.

An example of the use of arithmetics can be found in

Class variables

We also can use verbs and nouns as individuals, and, in rules, have variables ranging over them, as was implied by the inclussion of Noun and Verb in the discussion above. Within a fact, we can use a verb or a noun as subject, or as a modifier in the predicate. Within a rule, we can use a noun or verb variable anywhere a noun or a verb might be used.


We can add a method in_fact to subclasses of State, that will be called whenever a new fact with that verb in the predicate is added to the system (by the user or by extend ). This method takes as argument the fact added, as an instance of Fact.


This software is licenced under the GPL v3.

Enrique Pérez Arnaud © 2008-2009 <enriquepablo at google's mail domain>