When a plain module contains a set of submodules, one way of looking at what the module performs is by seeing it as a combination of the results of the different submodules. The definition of generic modules opens to the user the possibility of defining specific, and reusable, operations of composition of modules. A generic module is indeed an abstraction of a combination by means of giving names to the submodules that will be obtained only at application time. Generic modules are then operations (or functions) on modules. The technique to define generic modules is the same as to define functions, that is, it consists of the isolation of a piece of program, or module, from its context and its abstraction by specifying:
The obvious referent of this technique is functional programming [16, 4], where such abstractions (functions) form the basic program units. The functional body defines how to compute the output (results) in terms of the input (requirements). In Figure 15 we extend the syntax of module declarations of Figure 1 adding the generic modules declarations (the syntax is still not complete).
Figure 15: Syntax of generic module definition.
A method for building large KB systems consists of applying generic modules to previously built plain modules. Keeping the common parts in a generic module we can save code and time, and make the code much more understandable. The instantiation of a generic module over a set of arguments generates a plain module, and hence it can appear in the code in the same places as a module declaration does.
Consider the following example of microbiological analysis of samples for pneumonia diagnosis (Bacter-IA application). Some data can be obtained from a gram analysis of a sample (for instance, DCGP). These data can be obtained from different gram analysis over different samples (of sputum, of lung, or bronchoaspirated) to deduce the germ causing the illness (for instance pneumococcus). In this case it is not necessary to define a different problem solution for each type of analysis; it would be enough to define a generic problem solution depending on the kind of analysis.
Module Find_Germ (X) = Begin Export pneumococcus Deductive knowledge Dictionary: ... Rules: R001 If X/DCGP then conclude pneumococcus is possible ... End deductive End
The parameters of a generic module are, as we said before, abstracted submodules. These parameter names are unbound until the instantiation of the generic module. If we want to refer to the exported facts of the submodules that will be bound at application time we must build a path using the names of the parameters (for instance, in the rule of module Find_Germ a reference to the fact DCGP of a module eventually bounded is written X/DCGP). An example of the instantiation of the generic module seen above with data from a sputum sample is the following:
Module Find_Germ_Sputum = Find_Germ (Sputum_Gram)
The parameters of a generic module are submodules hidden outside the generic module, where hidden has the standard meaning and no access is allowed to the export interface or submodules of a hidden submodule. For instance, the submodule Sputum_Gram is hidden outside the new module Find_Germ_Sputum. So a reference like Find_Germ_Sputum/Sputum_Gram/DCGP will be detected by the compiler and an error will be raised.
A generic module makes use of the exported facts of the module bound to its module parameters, so a parameter cannot be bound to any module, but only to modules exporting the facts required in the body of the generic module. For instance, the module Sputum_Gram must export the facts needed in the rules of the generic module Find_Germ.
Milord II supports the process of incremental KB building by means of generic modules. Hence, whenever the definition of a generic module changes, the changes are reflected in the rest of the program. The way to do it is just to repeat the module applications that refer to the modified module. This re-linking process is automatised by the compiler, so that the user gets rid of this task.