tuProlog: Making Prolog Ubiquitous

By
Enrico Denti
Andrea Omicini
Roberta Calegari
Alma Mater Studiorum–Università di Bologna, Italy

Abstract

In the next decades, the emergence of complex intelligent systems is going to open a plethora of new opportunities for logic programmers, capable of injecting Prolog programs within adaptive, pervasive, self-organising, knowledge-intensive systems, and integrating them with all the sorts of different programming languages and paradigms, over computing platforms of any kind.
Suitable tools are then required, which could promote multi-language integration and multi-platform deployment, while ensuring both conceptual and technical coherence.
The tuProlog logic programming framework is precisely heading in that direction.

tuProlog

1 Introduction

Nowadays, the needs for intelligent pervasive systems are opening new perspectives for logic programming. At the same time, they also impose novel requirements for logic-based development frameworks, which should allow logic programmers to easily integrate Prolog chunks with other programming languages, and to freely range over a multiplicity of devices and platforms, including mobile devices such as smartphones and tablets. This is the main motivation behind the development of the tuProlog logic programming framework [7 , 2], which is aimed at spreading the use of Prolog over any potential computational platform, and at making the integration with mainstream object-oriented languages and middlewares as easy and straightforward as possible.

Accordingly, tuProlog can be exploited by different sort of programmers in different ways, and from different perspectives. More precisely:

  • the Prolog programmer can exploit the tuProlog IDE to consult, edit, and run Prolog programs upon any of the supported platforms—Java, .NET, Android, Eclipse;
  • the Java programmer can add tuProlog to a Java project to bring the power of logic programming to the Java world, thus approaching multi-paradigm programming from the Java side [3];
  • the Android programmer can add tuProlog to his/her Android project in quite the same way, since Java is also the prominent Android development language;
  • the .NET programmer, analogously, can add tuProlog to any Visual Studio project, developed in possibly any .NET language—not just C#–, thus approaching multi-paradigm/multi-language programming from the .NET side.
  • finally, the skilled multi-paradigm/multi-language developer can also exploit the multi-paradigm perspective endorsed by tuProlog to build hybrid Java+Prolog/.NET+Prolog applications to be run from the Prolog side — that is, Prolog applications that delegate some “imperative” tasks to the Java/.NET world, exploiting tuProlog both as a Prolog engine and as a mediator between the two paradigms/worlds. This is what the tuProlog plugin for Eclipse is for: by providing an ad-hoc tuProlog perspective, specific views over the Prolog and Java worlds are available at the same time in a coherent, effective, Eclipse-compliant way (No such plugin is currently available for the Visual Studio ID).

2 Basic Features in tuProlog

tuProlog is an open-source, light-weight Prolog framework for distributed applications and infrastructures, released under the LGPL license, available from [7]. Developed in/upon Java, which still remains the main reference platform, tuProlog is currently available also for the Microsoft .NET, Android and Eclipse plugin platforms.

Unlike most Prolog programming environments, aimed at providing a very efficient (yet monolithic) stand-alone Prolog system, tuProlog is explicitly designed to be minimal, dynamically configurable, naturally integrated with Java and .NET so as to support multi-paradigm/multi-language programming in a straightforward way, and easily deployable.

  • Minimality means that its core contains only the Prolog engine essentials—roughly speaking, the resolution engine and some related basic mechanisms: any other feature is implemented via libraries (Currently, for instance, tuProlog core is 155KB, while the JAR/APK archive to be distributed is less than 500 KB in size)
  • Configurability is the necessary counterpart of minimality, enabling users to customise their tuProlog system so to fit their own needs. Libraries provide packages of predicates, functors and operators, and can be loaded and unloaded in a tuProlog engine both statically and dynamically: several standard libraries are included in the tuProlog distribution, whereas users can develop their own—either in Prolog, in Java/.NET language, or in a hybrid mix of the two.
  • Easy deployability means that the installation requirements are minimal, and that the installation procedure is typically as simple as copying the proper archive to the desired folder (the Eclipse plugin and Android versions need to be installed as required by the hosting platforms).In Java, for instance, this currently means a single 474KB JAR le, or a 240KB APK archive for Android (the .NET version is slightly larger). The only somehow notably larger le (1.5MB) is the Eclipse plugin, whose installation has to conform to the Eclipse platform requirements.
  • Finally, tuProlog also supports interoperability with both Internet standard patterns (such as TCP/IP, RMI, CORBA) and coordination models and languages.

The latter aspect, in particular, is currently developed in the context of the TuCSoN coordination infrastructure [6 , 8], which provides logic-based, programmable tuple spaces (called tuple centres [5]) as the coordination media for distributed processes and agents.

 

3 Going Multi-paradigm & Multi-platform

Multi-paradigm programming is perhaps the foremost original feature of tuProlog. Intentionally designed to support a straightforward, pervasive, multi-language/multi-paradigm integration, tuProlog makes it possible to:

  • Use any Java/.NET class, library, object directly from the Prolog code, with no need of pre-declarations, awkward syntax, etc.; tuProlog fully supports parameter passing from/to the two worlds, without unnecessarily intermixing the two languages and computational models. This choice preserves a priori their own semantics, bringing the expressiveness of the object-oriented platforms (e.g., Java Swing, JDBC, .NET classes, etc.) to the Prolog world.
  • Use any tuProlog engine directly from the Java/.NET code—as one would do with any other Java libraries/.NET assemblies. Again, full parameter passing is allowed from/to the two worlds in a non-intrusive way. This makes it possible to inject and exploit “logic programming” intelligence into virtually any Java/.NET application.
  • Augment tuProlog by defining multi-language new libraries: pure Prolog libraries, object-oriented libraries (Java, .NET), mixed libraries (Prolog + OO language).
  • Augment Java/.NET with new methods defined in Prolog in a declarative way, via the so-called ‘P@J’/‘P@Net’ framework.

tuProlog supports multi-paradigm / multi-language programming between Prolog and the object-oriented world in a complete, four-dimensional way. While for the standard version of tuProlog “object-oriented language” typically means Java, the tuProlog.NET porting allows any .NET language to be used, too. As a result, the four multi-paradigm dimensions of tuProlog can be summarised as follows:

  • using the OO Language from Prolog
  • using Prolog from the OO language
  • augmenting Prolog via some OO language
  • augmenting the OO Language via Prolog

Here, using means that a language (along with the corresponding programming paradigm) is accessed and exploited from the other, whereas augmenting means that a language (and the corresponding programming paradigm) is exploited to increase – that is, to add features to – the other in some way.

 

Schermata13

4 Java/Prolog integration in tuProlog

tuProlog integrates Prolog and Java so that both can use each other, and augment each other. In particular, being first of all a Java-based Prolog programming framework, tuProlog provides a fully bi-directional integration between Java and Prolog, by making it possible

  • using Java from Prolog, through the JavaLibrary
  • using Prolog from Java, through tuProlog API
  • augmenting Prolog via Java, by developing Java-based tuProlog libraries
  • augmenting Java via Prolog, through the P@J framework [1]

4.1 Using Java from Prolog

First of all, tuProlog allows logic programmers to access the resources of the object-oriented world (objects, classes, methods, etc) in a straightforward way, avoiding the intricacies (object and method pre-declarations in some awkward syntax, pre-compilations, etc) that are typically found in other Prolog systems [3]. The unique tuProlog approach keeps the two computational models clearly separate, so that neither the declarative style of Prolog nor the imperative/object-oriented style of Java affect each other.

This feature is provided by the JavaLibrary library, which is organised around two basic bricks:

  • a mapping between object types and suitable Prolog types;
  • a set of predicates to perform operations (object creation, method call, etc.) on Java objects.

In this way, any Java package, library, etc. is accessible from within Prolog: so, for instance, Swing classes can be exploited to build the graphical support of a Prolog program. The same holds for JDBC to access databases, for the socket package to provide network access, for RMI to access remote Java objects, and so on.

JavaLibrary predicates allow Prolog to access, manipulate and interact with Java objects and classes in a complete way, including static members, arrays, property selection, type casts, up to class loading and dynamic compilation. Listings 1 and 2 report two simple examples: in the former, a Java Swing object is created and exploited from Prolog, enabling tuProlog to implement a basic Swing GUI in four lines of code; in the latter, the user class Counter is exploited in several ways, creating and manipulating an instance (first) and an array of Counters (later).

 


Listing 1: Creating and using a Swing component from tuProlog. A JFileChooser instance is created and bound to the Prolog variable Dialog, which is then used to call two instance methods via the <-/2 and (<-,returns)/3 operators. The latter form binds the return value to the Prolog variable File, which is then exploited to retrieve the corresponding FileName – that is, the predicate output – via the getName method.
test_open_file_dialog(FileName) :-
  java_object(’javax.swing.JFileChooser’, [], Dialog),
  Dialog <- showOpenDialog(_),
  Dialog <- getSelectedFile returns File,
  File <- getName returns FileName.

 


Listing 2: Creating and using a user-defined Counter object. The user-defined Counter class (not shown) is exploited: this class defines two constructors, the default one and one taking a string argument—the counter name, a setValue/getValue method pair, an inc method to increment to counter’s value and a static getVersion method. The name property is publicly accessible. The program creates a Counter instance, bounds it to the Prolog atom myCounter and exploits it to set the counter value to 5 via the setValue method, increment it via inc, and retrieve the new value calling getValue: the returned value, bound to the Prolog variable Value, is finally printed normally in Prolog. In the next lines, the static getVersion method is analogously called and the version number printed. The public name property is also directly read via dot notation, and subsequently overwritten with the new name MyCounter2. Finally, a Java array of ten Counter objects is created, and its reference – bound to the Prolog ArrayOfCounters variable – used to assign the previously-created myCounter instance to the array cell of index 0.
?-java_object(’Counter’, [’MyCounter’], myCounter),
 myCounter <- setValue(5),
 myCounter <- inc,
 myCounter <- getValue returns Value,
 write(Value), nl,
 class(’Counter’) <- getVersion return Version,
 write(Version), nl,
 myCounter.name <- get(Name),
 class(’java.lang.System’).out <- get(Out),
 Out <- println(Name),
 myCounter.name <- set(’MyCounter2’),
 java_object(’Counter[]’, [10], ArrayCounters),
 java_array_set(ArrayCounters, 0, myCounter).

The development of this kind of application can be actively supported by the tuProlog Eclipse plugin, allowing both Java and Prolog sides of the application to be observed simultaneously.

Last but not least, it is worth mentioning that beyond fully supporting ISO Prolog exceptions, tuProlog is also capable of intercepting and handling the Java exceptions possibly raised by the execution of constructors/methods on Java objects accessed from the Prolog world.

4.2 Using Prolog from Java

The tuProlog API allow Java to exploit Prolog engines: objects can be instantiated that represent Prolog entities (terms, atoms, lists, variables, numbers, etc, but also Prolog engines, libraries, and theories), which can then be used to submit queries and get the results back to the Java world. For instance, Listing 3 reports a Java program querying a tuProlog engine for a single solution, while the program in Listing 4 queries its tuProlog engine for multiple solutions.

 


Listing 3: One single solution. A Prolog engine solves a query involving the built-in append/3 predicate. The solution is retrieved via the SolveInfo object and printed normally in Java.
import alice.tuprolog.*;

public class Example1 {
    public static void main(String[] args) throws Exception {
      Prolog engine = new Prolog();
      SolveInfo info = engine.solve("append([1],[2,3],X).");
      System.out.println(info.getSolution());
    }
}

 


Listing 4: Multiple solutions. Unlike Listing 3, the query allows now for multiple solutions, retrieved one at a time by a Java loop that breaks when the engine has no further open alternatives.
import alice.tuprolog.*;

public class Example2 {
   public static void main(String[] args) throws Exception {
     Prolog engine = new Prolog();
     SolveInfo info = engine.solve("append(X,Y,[1,2]).");
     while (info.isSuccess()) {     
        System.out.println("solution: " + info.getSolution() + " - bindings: " + info);
      if (engine.hasOpenAlternatives()) {
         info = engine.solveNext();
      }
      else break;
    }
 }
}

4.3 Augmenting Prolog via Java

Augmenting Prolog from Java means exploiting the Java language to expand Prolog: this is achieved by allowing new tuProlog libraries to be developed in Java. The basic idea is that a tuProlog predicate is mapped onto a Java method of “similar” name—more precisely, the same name plus the _arity suffix. Once compiled and put in the JVM classpath, the library can be loaded and used normally by the tuProlog runtime.

Listing 5 shows a simple library, TestLibrary, which defines an evaluable functor (sum/2) and two predicates (println/1 and invert/2). Once compiled, the new library can be loaded in a tuProlog engine either from the Prolog side (via the load_library/1 predicate) or from the Java side (via the loadLibrary method of the Prolog class)—depending on whether the application has to be Prolog-driven (Subsection 4.1) or Java-driven (Subsection 4.2). Prolog users can also exploit the GUI library manager tool.

 


Listing 5: TestLibrary: a tuProlog library written in Java. The new Prolog evaluable functors (sum/2) and predicates (println/1, invert/2) are defined as Java methods with proper names.
import alice.tuprolog.*;

public class TestLibrary extends Library {
  // functor sum(A,B)
  public Term sum_2(Number arg0, Number arg1){
  float  n0 = arg0.floatValue();
  float  n1 = arg1.floatValue();
  return new Float(n0+n1);
  }
  // predicate println(Message)
  public boolean println_1(Term arg){
  System.out.println(arg);
  return true;
  }
  // predicate invert(StringIn,StringOut)
  public boolean invert_2(Term in, Var out){
    String s1 = null, s2 = "";
    if (in instanceof Var) s1 = in.getTerm().toString();
    else s1 = in.toString();
    for(int i=0; i<s1.length(); i++){
      char ch = s1.charAt(i);
      if (ch==’$\backslash$’) continue;
      if (Character.isUpperCase(ch))
         s2 += Character.toLowerCase(ch);
      else
         s2 += Character.toUpperCase(ch);
   }
  return out.unify(getEngine(),new Struct(s2));
 }
}

Hybrid Java+Prolog libraries are also possible, and are typically used to define a non-deterministic predicate in Prolog on top of a deterministic Java predicate: an example is reported in Listing 6.

 


Listing 6: HybridLibrary: a hybrid (Java+Prolog) library. A hybrid Java + Prolog library defines a non-deterministic Prolog predicate (myprint/1) on top of other existing predicates. The Prolog part is conventionally encoded as a string returned by the getTheory method.
public class HybridLibrary extends TestLibrary {
 public String getTheory(){
  return "myprint(X) :- println(X).\n" + 
         "myprint(X) :- invert(X,Y), myprint(Y).\n";
 }
}

4.4 Augmenting Java via Prolog

The basic idea here is to exploit Prolog as an implementation language for some abstract Java methods: the necessary Prolog code is embedded in Java as a suitable annotation. It is then up to the tuProlog runtime to automatically create a Java implementation of this method behind-the-scenes. Of course, proper conventions are needed for Prolog predicates names, argument matching, etc.; an example is reported in Listing 7, and its use is depicted in Listing 8.

 


Listing 7: Perm: a Java class augmented via Prolog. The Java class Perm exploits Prolog to implement its formally-abstract permutation method. The Prolog code is embedded in the @PrologMethod annotation, which takes the form of an array of string clauses.
import alice.tuprologx.pj.annotations.*;
import alice.tuprologx.pj.engine.*;
import alice.tuprologx.pj.model.*;
import alice.tuprologx.pj.meta.*;
import java.util.List;
import java.util.ArrayList;

abstract class Perm{
   @PrologMethod ( clauses = {
   "permutation([],[]).",
   "permutation(U,[X|V]):-remove(U,X,Z),permutation(Z,V).",
   "remove([X|T],X,T).",
   "remove([X|U],E,[X|V]):-remove(U,E,V)."
 })
 public abstract < $X extends List<Int>, $Y extends List<Int> >
   Iterable<$Y> permutation($X list);
}

 


Listing 8: A sample program using the Perm class (Listing 7). Factory method PJ.newInstance creates an instance of the formally-abstract Perm class, on which the permutation method is then called. Notice the Arrays.asList method, that exploits the Java shortcut syntax for varargs.
public class PJexample {
   public static void main(String[] args) throws Exception {
     java.util.Collection<Integer> v = java.util.Arrays.asList(1,2,3);
     Perm p=PJ.newInstance(Perm.class);
     for (List<Int> list : p.permutation(new List<Int>(v))) {
       System.out.println(list.toJava());
     }
   }
 }

5 Mobile Prolog: tuProlog on Android

The almost ubiquitous presence of Java on today computational devices is the most obvious premise to the potential ubiquity of tuProlog. The other – possibly less obvious – premise is its minimality, particularly relevant in the era of pervasive scenarios and mobile devices, often featuring scarce computational resources.

This is why Android is the platform of choice for mobility in tuProlog, which can be seen both as a Prolog usage platform and as a tuProlog development platform. The former aspect simply means that tuProlog is also available as an Android app, which wraps the same core (physically: the same JAR) with an ad-hoc GUI specifically designed for touch-based devices. This guarantees that the same built-ins, libraries, etc. are available on Android as on any other tuProlog-supported platform, yet in a novel interaction style

The latter aspect is instead the most relevant direct consequence of tuProlog being written in Java: since Java is also the development language of Android applications, the whole tuProlog Java API – and therefore tuProlog intelligence – is available to the Android developer by simply adding the tuProlog JAR to the Eclipse/Android project.

 

6 Bridging Multiple Languages with tuProlog.NET

The porting of tuProlog on .NET represents the last step towards the full spreading of Prolog over multiple platforms and a multiplicity of programming languages, based on the intrinsic features of the .NET framework.

On the one hand, the technical issue is quite simple: tuProlog.NET is obtained by automatic conversion of the Java bytecode via IKVM.NET [4], an efficient open source tool that supports the whole Java language, with minimal exclusions. So, the resulting system and GUI is identical to Java’s, and so is the Prolog user experience.

On the other hand, multi-paradigm integration is a much more complex matter, given that the .NET platform supports several different languages: so, the multi-paradigm experience needs is enriched here with the novel dimension of multi-language integration. Furthermore, the underlying presence of IKVM’s implementation of the JVM has the indirect effect of bringing Java to the .NET world, too, enabling further, interesting multi-language interaction scenarios.

 

6.1 Using .NET languages from Prolog

In tuProlog.NET, OOLibrary replaces JavaLibrary in enabling the access to the object-oriented world. Apart from more neutral, “Java-less” predicate names (e.g. new_object instead of java_object, etc.), the key difference is OOLibrary’s support to the simultaneous use of multiple .NET languages – and of Java, brought by IKVM – in the same application, thus leading tuProlog to work as a “bridger/orchestrator”, either in-front-of or behind-the-scenes, among .NET languages like C#, F#, etc. and Java, all together.

To this end, tuProlog.NET introduces language conventions as a way both to maintain language transparency – providing a uniform interface independently from the language-specific syntax details – and to bridge between the language-specific naming issues and the underlying Java-based machinery. Language conventions for the most common .NET languages (C#, F#, VB.NET and Java itself) are already included, but others can be defined by the programmer.

For instance, according to the C# and F# conventions, all the names, except for field names, should start with a capital letter, properties are compiled in a pair of get_/set_ methods, etc. The VB.NET convention differs for array handling, since arrays are defined with () instead of []. A Java convention is also available to provide the opposite transformation – i.e., changing Java method and field names to match the .NET standard – so that Java objects can be accessed as if they were .NET objects.

Listing 9 shows how a Student class developed in VB.NET can be used from tuProlog without and with and the proper language convention. Listing 10 shows the same situation with respect to a Java class. In both cases, plain access to the class is possible, but lets some language-specific details emerge that are unnatural on the host platform: the proper language convention, instead, bridges the gap, providing a more natural and “.NET-compliant” view. Listing 11 shows a comprehensive example where several.NET languages are used simultaneously, exploiting tuProlog ability to ensure the interoperability between Prolog primitive types (string, numbers, etc.) and the corresponding types of both the .NET and Java languages.

 


Listing 9: Accessing a Visual Basic Student class without/with the Visual Basic convention. In the former case (without VB convention), some language-specific details emerge (capitalised method names, get_Prop wrapper methods to access prop properties, get_StaticProperty methods instead of the dot notation, etc.) which are instead hidden in the latter case, where the language convention performs the required adjustments transparently.
accessingVBStudentWithoutVBConvention :-
 new_object(’VBStudent.Student’,[12345,joe,doe], Obj),
 Obj <- ’PrintStudent’ returns Student,
 Obj <- get_Id returns StudentNumber,
 class(’VBStudent.Student,VBStudent’) <- get_StaticProperty returns Value,
 new_object(’VBStudent.Student, VBStudent[]’,[10], Array).

accessingVBStudentWithVBConvention :-
 load_convention(’VBConvention.dll’,’VBConvention.VBDotNet’,Conv),
 new_object(Conv,’VBStudent.Student, VBStudent’,[12345,joe,doe], Obj),
 Obj <- printStudent returns Student,
 Obj.id <- get(StudentNumber),
 class(’VBStudent.Student, VBStudent’).staticProperty <- get(Value),
 new_object(Conv, ’VBStudent.Student, VBStudent()’,[10], Array).

 


Listing 10: Accessing a Java Student class without/with the Java convention. In the former case (without Java convention), some Java-specific details emerge (the lowercase printStudent method name) that remain hidden in the latter case.
accessingJavaStudentWithoutConvention :-
 new_object(’javastudent.Student’,[12345,joe,doe], Obj),
 Obj <- printStudent returns Student,
 Obj <- getId returns StudentNumber,
 class(’javastudent.Student’) <- printInfoUniv returns University,
 new_object(’javastudent.Student[]’,[10], Array).

accessingJavaStudentWithConvention :-
 load_convention(’JavaConvention.dll’,’JavaConvention.Java’,Conv),
 new_object(’javastudent.Student’,[12345,joe,doe], Obj),
 Obj <- ’PrintStudent’ returns Student,
 Obj <- getId returns StudentNumbers,
 class(’javastudent.Student’) <- printInfoUniv returns University,
 new_object(’javastudent.Student[]’,[10], Array).

 


Listing 11: Mixing Student classes in Java & .NET languages. Four different Student classes, written in three .NET languages and in Java, are exploited simultaneously. It is worth noting the transparent handling of primitive types – in particular, integer numbers in the sum expression – regardless of their origin.
sumAllExams(TotExams) :-
 load_convention(’CSharpConvention.dll’,’CSharpConvention.CSharp’, CSConv),
 load_convention(’FSharpConvention.dll’,’FSharpConvention.FSharp’, FSConv),
 load_convention(’VBConvention.dll’,    ’VBConvention.VBDotNet’, VBConv),
 load_convention(’JavaConvention.dll’,  ’JavaConvention.Java’, JConv),   
 new_object(CSConv, ’CStudent.Student, CStudent’,[12345,’joe’,’’], StudCS),
 new_object(FSConv, ’FStudent.Student, FStudent’,[52718,’Mary’,’’], StudFs),
 new_object(VBConv, ’VBStudent.Student, VBStudent’,[98650,’Jean’,’’], StudVB),
 new_object(JConv,  ’javastudent.Student’,[47638,’Holly’,’’], StudJa),
 StudCS.exams <- get(Ex1),
 StudFs.exams <- get(Ex2),
 StudVB.exams <- get(Ex3),
 StudJa <- getExams returns Ex4,
 TotExams is Ex1 + Ex2 + Ex3 + Ex4.

The interaction between Java and .NET is so tight yet transparent that not only Java existing classes can be exploited in tuProlog.NET directly (as in Listings 10 and 12), but that new Java classes can be dynamically compiled (thanks to the inner support of IKVM) from Java sources expressed as Prolog atoms, and used immediately after (Listing 13).

 


Listing 12: Exploiting a standard Java class “as is” from tuProlog.NET. The Java StringTokenizer class is used straight from tuProlog.NET as if it were a native .NET class.
useJavaClassAsIs :-    
  new_object(’java.util.StringTokenizer’, [’This is my string’], Tokenizer),
  Tokenizer <- nextToken returns Token1,
  write(Token1), nl.

 


Listing 13: Dynamically compiling and using a new Java class from a source expressed as a Prolog atom. A Java source, expressed as a Prolog atom, is dynamically compiled, then transparently converted to the .NET format (dll) by IKVM behind-the-scenes, and immediately exploited to instantiate an object (via the newInstance factory method), which is finally used on-the-fly.
dynamicCompilation :-
 java_class(’public class MyClass {
   public String showFileChooser(String title) {
     javax.swing.JFileChooser chooser = new javax.swing.JFileChooser();
     chooser.setDialogTitle(title);
     chooser.showOpenDialog(null);
     java.io.File file = chooser.getSelectedFile();
     return file.getName();
    }
  }’,
  ’MyClass’, [], C),
  new_object(’java.lang.String’,[’Select a file from tuProlog!’], Message),
   C <- newInstance returns Object,
   Object <- showFileChooser(Message) returns FileName,
   write(FileName).

As a last remark, it is worth noting that interoperability between .NET and Java classes becomes an issue, instead, when complex types (i.e., anything other than strings and primitive types) are involved in the same tuProlog.NET program, given that a Java object is inherently different inside, and therefore cannot be passed to a .NET method “as is”—and vice-versa. A possible workaround is to transform the complex data in some neutral form that tuProlog.NET could handle transparently also to/from Java – typically, some string-based representation – so as to overcome the cross-platform intrinsic “incommunicability”.

6.2 Using Prolog from .NET languages

.NET applications that exploit tuProlog.NET as an inner component to bring logic programming to the object-oriented world can be developed like any other .NET application, just adding a reference to the tuProlog assembly in the Visual Studio project. In fact, the automatic IKVM.NET conversion of the tuProlog JAR in the DLL format ensures that the same API and mapping presented in Section Subsection 4.2 for the Java case still apply.

 

6.3 Augmenting Prolog via .NET languages

tuProlog.NET libraries can be written both in any .NET language and in Java, thanks to the IKVM.NET support; again, the same syntactic conventions discusses for the Java case (Subsection 4.3) still apply. Libraries written in a .NET language just need to be compiled by a .NET compiler, while libraries written in Java need to be first compiled by the Java compiler and then translated to the DLL format by IKVM.NET. The only visible difference between tuProlog for Java and tuProlog.NET is where and how libraries are searched in the file system, since this operation adheres to the host platform conventions—and the .NET approach differs from Java’s.

 

6.4 Augmenting .NET languages via Prolog

Although the P@J framework (Subsection 4.4) remains internally available in tuProlog.NET because of the automatic translation performed by IKVM.NET, its operativity is limited to Java applications translated to .NET—that is, a .NET application can not be augmented in this way. The main reason lays in the type erasure technique adopted in Java to handle generic types, which contrasts with the approach adopted in .NET, where types are reified at run time. As a result, Java methods exploiting generic types do not match the analogous .NET methods at run time, and there is nothing IKVM.NET can do to reconstruct the removed type information.

For this reason, tuProlog.NET 2.7.x adopts a radically different approach, based on Microsoft Visual Studio code generators: the run-time approach of P@J, based on capturing and executing the inlined Prolog code, is replaced by a development-time approach, where the Prolog code is written in a stand-alone (.pl) file, and a suitable .NET class is automatically generated from such code, compiled to a DLL and transparently linked to the project every time the Prolog source file is modified—with a total integration with the Visual Studio build process. Current support is limited to Visual Studio 2010: the support to Visual Studio 2012 and 2013 is underway.

The code generator works on standard tuProlog sources – no modifications are required to support this inter-operability, though the generated C# (or VB.NET, etc.) class can be customized in name and namespace – and can operate either in static or dynamic mode. In the former case, the Prolog code is encapsulated in the .NET source when the class is generated, while in the latter the generated class contains only a loader, and the Prolog source remains separate: in this way, the Prolog code can be dynamically changed at a later time without affecting the imperative part of the application.

7 Conclusion

In the next decades, the emergence of complex intelligent systems is going to open a plethora of new opportunities for logic programmers, capable of injecting Prolog programs within adaptive, pervasive, self-organising, knowledge-intensive systems, and integrating them with all the sorts of different programming languages and paradigms, over computing platforms of any kind. This, quite obviously, will require the availability of suitable tools promoting multi-language integration and multi-platform deployment, and ensuring at the same time both conceptual and technical coherence.

Nowadays, our 15-years-long work with the tuProlog logic programming framework is precisely heading in that direction.

References

[1]    Maurizio Cimadamore and Mirko Viroli. Integrating Java and Prolog through generic methods and type inference. In Roger L. Wainwright, Hisham M. Haddad, Ronaldo Menezes, and Mirko Viroli, editors, 23th ACM Symposium on Applied Computing (SAC 2008), volume 1, pages 198–205, Fortaleza, Ceará, Brazil, 16–20 March 2008. ACM. Special Track on Programming Languages.

[2]    Enrico Denti, Andrea Omicini, and Alessandro Ricci. tuProlog: A light-weight Prolog for Internet applications and infrastructures. In I.V. Ramakrishnan, editor, Practical Aspects of Declarative Languages, volume 1990 of LNCS, pages 184–198. Springer, 2001. 3rd International Symposium (PADL 2001), Las Vegas, NV, USA, 11–12 March 2001. Proceedings.

[3]   Enrico Denti, Andrea Omicini, and Alessandro Ricci. Multi-paradigm Java-Prolog integration in tuProlog. Science of Computer Programming, 57(2):217–250, August 2005.

[4]    IKVM.NET. Home page. http://www.ikvm.net.

[5]   Andrea Omicini and Enrico Denti. From tuple spaces to tuple centres. Science of Computer Programming, 41(3):277–294, November 2001.

[6]    Andrea Omicini and Franco Zambonelli. Coordination for Internet application development. Autonomous Agents and Multi-Agent Systems, 2(3):251–269, September 1999. Special Issue: Coordination Mechanisms for Web Agents.

[7]    tuProlog. Home page. http://tuprolog.unibo.it.

[8]    TuCSoN. Home page. http://tucson.unibo.it.