SWI-Prolog Python interface
All Application Manual Name SummaryHelp

  • Documentation
    • Reference manual
    • Packages
      • SWI-Prolog Python interface
        • Introduction
        • Data conversion
        • Janus by example - Prolog calling Python
        • library(janus): Call Python from Prolog
        • Calling Prolog from Python
        • Janus and threads
        • Janus and signals
        • Janus versions
        • Janus as a Python package
        • Prolog and Python
        • Janus performance evaluation
        • Python or C/C++ for accessing resources?
        • Janus platforms notes
        • Compatibility to the XSB Janus implementation
        • Status of Janus

2 Data conversion

The bi-directional conversion between Prolog and Python terms is summarized in the table below. For compatibility with Prolog implementations without native dicts we support converting the {k1:v1, k2:v2, ...} to dicts. Note that {k1:v1, k2:v2} is syntactic sugar for {}(','(:(k1,v1), :(k2,v2))). We allow for embedding this in a py(Term) such that, with py defined as prefix operator, py{k1:v1, k2:v2} is both valid syntax as SWI-Prolog dict as as ISO Prolog compliant term and both are translated into the same Python dict. Note that {} translates to a Python string, while py({}) translates into an empty Python dict.

By default we translate Python strings into Prolog atoms. Given we support strings, this is somewhat dubious. There are two reasons for this choice. One is the pragmatic reason that Python uses strings both for identifiers and arbitrary text. Ideally we'd have the first translated to Prolog atoms and the latter to Prolog strings, but, because we do not know which strings act as identifier and which as just text, this is not possible. The second is to improve compatibility with Prolog systems that do not support strings. Note that py_call/3 and py_iter/3 provide the option py_string_as(Type) to obtain strings in an alternative format, where Type is one of atom, string, codes or chars.

Prolog Python Notes
Variable⟶ -(instantiation error)
Integer⟺ intSupports big integers
Rational⟺ fractions.Fraction()
Float⟺ float
@(none)⟺ None
@(true)⟺ True
@(false)⟺ False
Atom⟵ enum.Enum() Name of Enum instance
Atom⟺ StringDepending on py_string_as option
String⟶ String
string(Text)⟶ StringText is an atom, string, code- or char list
#(Term)⟶ Stringstringify using write_canonical/1 if not atomic
prolog(Term)⟶ janus.Term() Represents any Prolog term
Term⟵ janus.Term()
List⟶ List
List⟵ Sequence
List⟵ IteratorNote that a Python Generator is an Iterator
py_set(List)⟺ Set
-()⟺ ()Python empty Tuple
-(a,b, ... )⟺ (a,b, ... )Python Tuples. Note that a Prolog pair A-B maps to a Python (binary) tuple.
Dict⟺ DictDefault for SWI-Prolog
{k:v, ...} ⟺ DictCompatibility when using py_dict_as({})
py({})⟵ {} Empty dict when using py_dict_as({})
{k:v, ...} ⟶ DictCompatibility (see above)
py({k:v, ...})⟶ DictCompatibility (see above)
eval(Term)⟶ ObjectEvaluate Term as first argument of py_call/2
py_obj blob⟺ ObjectUsed for any Python object not above
Compound⟶ -for any term not above (type error)

The interface supports unbounded integers and rational numbers. Large integers (> 64 bits) are converted using a hexadecimal string as intermediate. SWI-Prolog rational numbers are mapped to the Python class fractions:Fraction.1Currently, mapping rational numbers to fractions uses a string as intermediate representation and may thus be slow.

The conversion #(Term) allows passing anything as a Python string. If Term is an atom or string, this is the same as passing the atom or string. Any other Prolog term is converted as defined by write_canonical/1. The conversion prolog(Term) creates an instance of janus.Term(). This class encapsulates a copy of an arbitrary Prolog term. The SWI-Prolog implementation uses the PL_record() and PL_recorded() functions to store and retrieve the term. Term may be any Prolog term, including blobs, attributed variables. Cycles and subterm sharing in Term are preserved. Internally, janus.Term() is used to represent Prolog exeptions that are raised during the execution of janus.query_once() or janus.query().

Python Tuples are array-like objects and thus map best to a Prolog compound term. There are two problems with this. One is that few systems support compound terms with arity zero, e.g., f and many systems have a limit on the arity of compound terms. Using Prolog comma lists, e.g., (a,b,c) does not implement array semantics, cannot represent empty tuples and cannot disambiguate tuples with one element from the element itself. We settled with compound terms using the - as functor to make the common binary tuple map to a Prolog pair.