I had written earlier about natural language generation using my iLangGen framework. I used a “template” text file which was instantiated dynamically based on predefined “grammars” and external data. The sample application I show-cased demonstrated its utility and versatility.
Today I would like to touch upon a few other “pattern” elements that can be embedded in the template. All these patterns, including the ability to specify grammar rules, make this template-based approach quite powerful and applicable in real-world applications.
Structure of Template File
The template file can have normal text that will be instantiated, as well as supporting code fragments (only Lisp is supported as of now).
The “text” section starts with the marker “@text” and ends with “@end”. Code section starts with the marker “@code” and ends with “@end”. In case many functions are to be defined, it might be convenient to keep the code in a separate file and reference it using “@code-file” marker.
Here is the overall structure example:
@code-file “utils.lisp”
@text
The actual template text goes here…
@end
Anything in this area (outside of sections) is ignored..
@code
Lisp code goes here…
@end
Supported Patterns
The text section contains the actual text that gets instantiated based on different patterns embedded in it.
A pattern is defined within the delimiters “{{“ and “}}”. The different patterns are
Grammar Pattern:
We saw this example in the earlier article. It is of the form {{Grammar::Non-Terminal}}. During instantiation, the grammar is invoked starting at the specified non-terminal.
Immediate Value:
This has the form {{! $1}}. The variable “$1” specifies the first argument passed to the template processor function. Allowed variables are “$1” … “$5”. As part of template expansion, the variable’s value is directly substituted at the place where the pattern appears.
Function Call:
Similar to the grammar pattern, function application gives tremendous expressive power to the template structure. It looks like this: {{function arg1 arg2 arg3}}. The arguments can be literals or the run-time parameters “$1” … “$5”.
Embedded Template:
It is possible to specify another template file to be instantiated and the result embedded as part of this template instantiation. The syntax is {{< another-template-file.txt}}. This is another feature of immense value since we can now allow template composition and hence take advantage of reusable structures.
Here is a sample template file.
The above template contains one “Immediate Value” pattern and two “Function Call” patterns. You can also see the code section that contains a single function definition and also a reference to an external code file. Here is the code file:
Instantiating the Template
Template instantiation occurs through the function call “process-template-file”. See the invocation below:
The first argument is the template file to be instantiated and the remaining arguments (optional) represent the run-time arguments “$1” … “$5” we mentioned earlier. You can see how the template gets instantiated.
This example does not use the “Embedded Template” pattern. I will discuss this pattern and its usage in detail in a future article.
Hope you find the idea interesting. iLangGen framework and the template-based generation engine are all written in LispWorks Lisp.
Have a great week!
Recent Comments