root/trunk/manuals/migration/index.html

Revision 4621, 20.5 KB (checked in by pmoura, 6 weeks ago)

Improved navigation bar in the XHTML manual pages.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1<?xml version="1.0" encoding="utf-8"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
3    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
4
5<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
6
7<head>
8    <meta http-equiv="content-type" content="application/xml+xhtml; charset=utf-8" />
9    <title>Logtalk: Prolog Integration and Migration Guide</title>
10    <link rel="stylesheet" href="../print.css" type="text/css" media="print"/>
11    <link rel="stylesheet" href="../screen.css" type="text/css" media="screen"/>
12</head>
13
14<body>
15
16<div class="navtop"><span><a href="../index.html">Contents</a></span> &gt; 
17    <span class="title">Prolog Integration and Migration Guide</span><span class="page"/>
18</div>
19
20
21<h1>Prolog Integration and Migration Guide</h1>
22
23<p>
24An application may include plain Prolog files, Prolog modules, and Logtalk objects. This is a perfectly valid way of developing a complex application and, in some cases, it might be the most appropriated solution. Modules may be used for legacy code or when a simple encapsulation mechanism is adequate. Logtalk objects may be used when more powerful encapsulation, abstraction, and reuse features are needed. Logtalk supports the compilation of source files containing both plain Prolog and Prolog modules. This guide provides tips for helping integrating and migrating plain Prolog code and Prolog module code to Logtalk. Step-by-step instructions are provided for encapsulating plain Prolog code in objects, converting Prolog modules into objects, and compiling and reusing Prolog modules as objects from inside Logtalk. An interesting application of the techniques described in this guide is a solution for running a Prolog application which uses modules on a Prolog compiler with no module system.
25</p>
26
27
28<h2>Source files with both Prolog code and Logtalk code<a id="hybrid"></a></h2>
29
30<p>
31Logtalk source files may contain plain Prolog code intermixed with Logtalk code. The Logtalk compiler just copies the plain Prolog code as-is to the generated Prolog file. With Prolog modules, it is assumed that the module code starts with a <code>module/1-2</code> directive and ends at the end of the file. There is no module ending directive which would allowed us define more than one module per file. In fact, most Prolog module systems always define a single module per file. Some of them mandate that the <code>module/1-2</code> directive be the first term on a source file. As such, when the Logtalk compiler finds a <code>module/1-2</code> directive, it assumes that all code that follows until the end of the file belongs to the module.
32</p>
33
34
35<h2>Encapsulating plain Prolog code in objects<a id="encapsulating"></a></h2>
36
37<p>
38Most applications consist of several plain Prolog source files, each one defining a few top predicates and auxiliary predicates that are not meant to be directly called by the user. Encapsulating plain Prolog code in objects allows us to make clear the different roles of each predicate, to hide implementation details, and to take advantage of other Logtalk features.
39</p>
40<p>
41Encapsulating Prolog code using Logtalk objects is easy. First, for each source file, add an opening object directive, <a title="Consult reference manual" href="../refman/directives/object1_5.html"><code>object/1</code></a>, to the beginning of the file and an ending object directive, <a title="Consult reference manual" href="../refman/directives/end_object0.html"><code>end_object/0</code></a>, to end of the file. Choose an object name that reflects the purpose of source file code (this is a good opportunity to reorganize your code if needed). Second, add <a title="Consult reference manual" href="../refman/directives/public1.html">public predicate directives</a> for the top-level predicates that are used directly by the user or called from other source files. Third, we need to be able to call from inside an object a predicate defined in other source file/object. The easiest solution, which has the advantage of not implying any modification to the predicate clauses, is to use the <a title="Consult reference manual" href="../refman/directives/uses2.html"><code>uses/2</code></a> directive. If your Prolog compiler supports cross-referencing tools, you may use them to help you make sure that all calls to predicates on other source files/objects are listed in the <a title="Consult reference manual" href="../refman/directives/uses2.html"><code>uses/2</code></a> directives. Compiling the resulting objects with the Logtalk <code>portability</code> flag set to <code>warning</code> will help you locate calls to predicates defined on other converted source files.
42</p>
43
44<h3>Prolog multifile predicates</h3>
45
46<p>
47Prolog multifile predicates are used when clauses for the same predicate are spread among several source files. When encapsulating plain Prolog code that uses multifile predicates, is often the case that the clauses of the multifile predicates get spread between different objects and categories. When calling such predicates, you often want to use not only local clauses but also clauses stored in ancestor objects or imported. However, these <em>inherited</em> clauses are overridden by the local ones. For ancestor objects, use the <em>super call</em> operator, <code>^^/1</code>, to get access to the overridden clauses. For imported categories, use the <em>message to self</em> operator, <code>::/1</code>, to get access to the overridden clauses. For example, assume a multifile predicate, <code>mp/2</code> with both local clauses and  clauses imported from a category. The solution is to add a local clause giving access to the imported clauses by using the <code>::/1</code> operator:
48</p>
49<pre>
50mp(..., ...).    % local clauses
51...
52mp(A, B) :-      % imported clauses
53    ::mp(A, B).
54</pre>
55<p>
56By adding the <em>gateway</em> clause after or before the local clauses, you can choose if the local clauses should be used before or after the overridden clauses.
57</p>
58<p>
59A more complicated scenario is when you have several files containing clauses for a multifile predicate. For example, assume that a multifile predicate named <code>mp/2</code> is defined in two files. In this case, start by defining a protocol containing the declaration of the multifile predicate:
60</p>
61<pre>
62:- protocol(ptc).
63
64    :- public(mp/1).
65
66:- end_protocol.
67</pre>
68<p>
69Second, for each file, define a category containing the corresponding clauses for the <code>mp/2</code> predicate:
70</p>
71<pre>
72:- category(ctg1,
73    implements(ptc)).
74
75    mp(1).    % clauses from the first file
76    mp(2).
77
78:- end_category.
79
80
81:- category(ctg2,
82    implements(ptc)).
83
84    mp(3).    % clauses from the first file
85    mp(4).
86
87:- end_category.
88</pre>
89<p>
90Next, define an object importing all the categories and defining aliases to the imported predicates:
91</p>
92<pre>
93:- object(obj,
94    implements(ptc),
95    imports(ctg1, ctg2)).
96
97    :- alias(ctg1, mp/1, ctg1_mp/1).
98    :- alias(ctg2, mp/1, ctg2_mp/1).
99
100    mp(X) :-
101        ::ctg1_mp(X).
102    mp(X) :-
103        ::ctg2_mp(X).
104
105:- end_ object.
106</pre>
107<p>
108The predicate aliases above are needed to allow access to the overridded clauses of the <code>mp/1</code> predicate (by default, the clauses from  <code>ctg1</code> would override the clauses from the <code>ctg2</code> category as a consequence of the predicate lookup mechanism).
109</p>
110<p>
111Compiling and loading the above Logtalk entities allows you to access all clauses of the former multifile predicate. For example:
112</p>
113<pre>
114| ?- obj::mp(X).
115
116X = 1 ;
117X = 2 ;
118X = 3 ;
119X = 4
120yes
121</pre>
122
123<h2>Converting Prolog modules into objects<a id="converting"></a></h2>
124
125<p>
126Converting Prolog modules into objects allows an application to run on a wider range of Prolog compilers, overcoming module compatibility problems. Not all Prolog compilers support a module system. Among those Prolog compilers which support a module system, the lack of standardization leads to several issues, specially with operators and meta-predicates. In addition, the conversion allows you to take advantage of Logtalk more powerful abstraction and reuse mechanisms such as separating interface from implementation.
127</p>
128<p>
129Converting a Prolog module into an object is easy as long as the directives used in the module are supported by Logtalk (see below). First, convert the module <code>module/1</code> directive into an opening object directive, <a title="Consult reference manual" href="../refman/directives/object1_5.html"><code>object/1</code></a>, using the module name as the object name. For <code>module/2</code> directives apply the same conversion and convert the list of exported predicates into Logtalk <a title="Consult reference manual" href="../refman/directives/public1.html">public predicate directives</a>. Second, add a closing object directive, <a title="Consult reference manual" href="../refman/directives/end_object0.html"><code>end_object/0</code></a>, at the end of the module code. Third, convert any <code>export/1</code> directives into public predicate directives. Fourth, convert any <code>use_module/2</code> directives into Logtalk <a title="Consult reference manual" href="../refman/directives/uses2.html"><code>uses/2</code></a> directives. Any <code>use_module/1</code> directives are also converted into Logtalk <a title="Consult reference manual" href="../refman/directives/uses2.html"><code>uses/2</code></a> directives but you will need first to find out which predicates your module uses from the specified modules. Fifth, convert any <code>meta_predicate/1</code> directives into Logtalk <a title="Consult reference manual" href="../refman/directives/meta_predicate1.html"><code>meta-predicate/1</code></a> directives by replacing the module meta-argument indicator, <code>:</code>, into the Logtalk meta-predicate indicator, <code>::</code>. Arguments which are not meta-arguments are represented by the <code>*</code> character. Compile the resulting objects with the Logtalk <code>portability</code> flag set to <code>warning</code> to help you locate calls to predicates defined on other converted modules.
130</p>
131
132
133<h2>Compiling Prolog modules as objects<a id="compiling"></a></h2>
134
135<p>
136An alternative to convert Prolog modules into objects is to just compile the modules as objects. This has the advantage of not implying any code changes. However, this is only possible for modules containing only predicates clauses and Logtalk supported directives (see below). Assuming that is the case, you may compile a Prolog module as an object by changing the source file name extension to <code>.lgt</code> and then using the <a title="Consult user manual" href="../userman/programming.html#compiling"><code>logtalk_load/1-2</code></a> and <a title="Consult user manual" href="../userman/programming.html#compiling"><code>logtalk_compile/1-2</code></a> predicates (set the Logtalk <code>portability</code> flag set to <code>warning</code> to help you catch any unnoticed cross-module predicate calls). This allows you to reuse existing module code as objects. However, there are some limitations that you should be aware. These limitations are a consequence of the lack of standardization of Prolog module systems. Currently, Logtalk supports the following module directives:
137</p>
138<dl>
139    <dt><code>module/1</code></dt>
140        <dd>The module name becomes the object name.</dd>
141    <dt><code>module/2</code></dt>
142        <dd>The module name becomes the object name. The exported predicates become public object predicates.</dd>
143    <dt><code>use_module/2</code></dt>
144        <dd>This directive is compiled as a Logtalk <a title="Consult reference manual" href="../refman/directives/uses2.html"><code>uses/2</code></a> directive in order to ensure correct compilation of the module predicate clauses. Note that the module specified on the directive is not automatically loaded by Logtalk (as it would be when compiling the directive using Prolog instead of Logtalk; the programmer may also want the specified module to be compiled as an object).</dd>
145    <dt><code>export/1</code></dt>
146        <dd>Exported predicates are compiled as public object predicates. The argument must be a predicate indicator (<code>Functor/Arity</code>) or a list of predicate indicators.</dd>
147    <dt><code>meta_predicate/1</code></dt>
148        <dd>Module meta-predicates become object meta-predicates. Only predicate arguments marked as <code>:</code> are interpreted as meta-arguments. However, note that Prolog module meta-predicates and Logtalk meta-predicates don't share the same exact semantics; check results carefully.</dd>
149</dl>
150<p>
151Logtalk supports the use of the <a title="Consult user manual" href="../userman/programming.html#programming_libraries"><em>library(name)</em> notation</a> on the <code>module/1-2</code> and <code>use_module/2</code> directives (assuming there is an entry for the library on the <a title="Consult reference manual" href="../refman/builtins/logtalk_library_path2.html"><code>logtalk_library_path/2</code></a> table).
152</p>
153<p>
154When compiling modules as objects, you probably don't need event support turned on. Thus, you may want to use the compiler option <code>events(off)</code> with the Logtalk compiling and loading built-in methods for a small performance gain for the compiled code.
155</p>
156
157<h3>Current limitations and workarounds<a id="limitations"></a></h3>
158
159<p>
160Note that <code>use_module/1</code> directives are not directly supported. Therefore, this directives must be converted into <code>use_module/2</code> directives by finding which predicates exported by the specified module are imported into the module containing the directive. Automating the conversion would imply loading the module without re-interpreting it as an object, which might not be what the user intended. Nevertheless, finding the names of the imported predicates is easy. First, comment out the <code>use_module/1</code> directives and compile the file (making sure that the compiler flag <code>misspelt</code> is set to <code>warning</code>). Logtalk will print a warning with a list of predicates that are called but never defined. Second, use these list to replace the <code>use_module/1</code> directives by <code>use_module/2</code> directives. You should then be able to compile the modified Prolog module as an object.
161</p>
162<p>
163Changing the extension of a module source file to <code>.lgt</code> in order to be able to compile it as Logtalk source file is not always feasible. An alternative is to create symbolic links or shortcuts for the module files using <code>*.lgt</code> names. In addition, for avoiding conflicts between the Logtalk generated Prolog files and the module files, create the links on a different directory and add a library entry for the directory using the predicate <a title="Consult reference manual" href="../refman/builtins/logtalk_library_path2.html"><code>logtalk_library_path/2</code></a>. For example, on a POSIX operating-system with <code>library/*.pl</code> module source file names, the links can be easily created by running the following bash shell commands:
164</p>
165<pre>$ mkdir lgtlib
166$ cd lgtlib
167$ for i in ../library/*.pl; do ln -sf $i `basename $i .pl`.lgt; done</pre>
168<p>
169The symbolic links or shortcuts can also be easily created on most operating-systems using the GUI tools.
170</p>
171
172
173<h2>Dealing with proprietary Prolog directives<a id="proprietary"></a></h2>
174
175<p>
176Most Prolog compilers define proprietary, non-standard directives that may be used in both plain code and module code. Logtalk will generate compilation errors on source files containing these directives unless you first specify how the directives should be handled. Three actions are possible and can be specified, on a per-directive basis, on the Prolog configuration files: ignoring the directive (i.e. do not copy the directive, although a goal can be proved as a consequence), rewriting and copy the directive to the generated Prolog files, or rewriting and recompiling the resulting directive. Each action is specified using, respectively, the predicates: <code>'$lgt_ignore_pl_directive'/1</code>, <code>'$lgt_rewrite_and_copy_pl_directive'/2</code>, and <code>'$lgt_rewrite_and_recompile_pl_directive'/2</code>. For example, assume that a given Prolog compiler defines a <code>comment/2</code> directive for predicates using the format:
177</p>
178<pre>:- comment(foo/2, "Brief description of the predicate").</pre>
179<p>
180We can rewrite this predicate into a Logtalk <code>info/2</code> directive by defining a suitable clause for the <code>'$lgt_rewrite_and_recompile_pl_directive'/2</code> predicate:
181</p>
182<pre>'$lgt_rewrite_and_recompile_pl_directive'(comment(F/A, String), info(F/A, [comment is Atom])) :-
183    atom_codes(Atom, String).</pre>
184<p>
185This Logtalk feature can be used to allow compilation of legacy Prolog code without the need of changing the sources. When used, is advisable to set the <code>portability/1</code> compiler flag to <code>warning</code> in order to more easily identify source files that are likely non-portable across Prolog compilers.
186</p>
187<p>
188A second example, using the <code>'$lgt_ignore_pl_directive'/1</code> hook predicate:
189</p>
190<pre>'$lgt_ignore_pl_directive'(load_foreign_files(Files,Libs,InitRoutine)) :-
191    load_foreign_files(Files,Libs,InitRoutine).</pre>
192<p>
193In this case, although the directive is not copied to the generated Prolog file, the foreign library files are loaded as a side-effect of calling the hook predicate.
194</p>
195
196
197<h2>Calling Prolog module predicates<a id="calling"></a></h2>
198
199<p>
200Logtalk allows you to send a message to a module in order to call one of its predicates. This is usually not advised as it implies a performance penalty when compared to just using the <code>Module:Call</code> notation. Note that this only works if there is no object with the same name as the module you are targeting. This feature is needed to properly support compilation of modules containing <code>use_module/2</code> directives as objects. If the modules specified in the <code>use_module/2</code> directives are not compiled as objects but are instead loaded as-is by Prolog, the exported predicates would need to be called using the <code>Module:Call</code> notation but the converted module will be calling them through message sending. Thus, this feature ensures that, on a module compiled as an object, any predicate calling other module predicates will work as expected either these other modules are loaded as-is or also compiled as objects.
201</p>
202<p>
203Logtalk supports the use of <code>use_module/2</code> directives in object and categories. In this case, these directives are parsed in a similar way to Logtalk <a title="Consult reference manual" href="../refman/directives/uses2.html"><code>uses/2</code></a> directives, with calls to the specified module predicates being automatically translated to <code>Module:Goal</code> calls. For example, assume a <code>clpfd</code> Prolog module implementing a finite domain constraint solver. You could write:
204</p>
205<pre>
206:- object(puzzle).
207
208    :- public(puzzle/1).
209
210    :- use_module(clpfd, [all_different/1, ins/2, label/1, (#=)/2, (#\=)/2]).
211
212    :- initialization((puzzle(As+Bs=Cs), label(As), write(As+Bs=Cs), nl)).
213
214    puzzle([S,E,N,D] + [M,O,R,E] = [M,O,N,E,Y]) :-
215        Vars = [S,E,N,D,M,O,R,Y],
216        Vars ins 0..9,
217        all_different(Vars),
218                  S*1000 + E*100 + N*10 + D +
219                  M*1000 + O*100 + R*10 + E #=
220        M*10000 + O*1000 + N*100 + E*10 + Y,
221        M #\= 0, S #\= 0.
222
223:- end_object.
224</pre>
225<p>
226As a general rule, the Prolog modules should be loaded (e.g. in the auxiliary Logtalk loader files) before compiling objects that make use of module predicates. This is mandatory whenever the module exports operator declarations that you want to use in your objects and categories (as in the example above).
227</p>
228<p>
229Logtalk supports the declaration of predicate aliases in <code>use_module/2</code> directives used within object and categories. For example, the ECLiPSe IC Constraint Solvers define a <code>::/2</code> variable domain operator that clashes with the Logtalk <code>::/2</code> message sending operator. We can solve the conflict by writing:
230</p>
231<pre>:- use_module(ic, [alldifferent/1, (::)/2:ins/2, (#=)/2]).</pre>
232<p>
233With this directive, calls to the <code>ins/2</code> predicate alias will be automatically compiled by Logtalk to calls to the <code>::/2</code> predicate in the <code>ic</code> module.
234</p>
235
236<div class="footer">
237    <div class="copyright">
238        <span>Copyright &copy; <a href="mailto:pmoura@logtalk.org">Paulo Moura</a> &mdash; <a href="http://logtalk.org">Logtalk.org</a></span><br/> 
239        <span>Last updated on: August 16, 2008</span>
240    </div>
241    <div class="navbottom">
242        <span><a href="../glossary.html">glossary</a></span><br/>
243        <span><a href="http://validator.w3.org/check/referer">XHTML</a> + <a href="http://jigsaw.w3.org/css-validator/check/referer">CSS</a></span>
244    </div>
245</div>
246
247</body>
248
249</html>
Note: See TracBrowser for help on using the browser.