- Documentation
- Reference manual
- Packages
- SWI-Prolog Python interface
- Introduction
- Data conversion
- Janus by example
- library(janus): Call Python from Prolog
- Calling Prolog from Python
- Janus and threads
- 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
- SWI-Prolog Python interface
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(string) to obtain a string if this is
desirable.
| Prolog | Python | Notes | |
| Variable | ⟶ | - | (instantiation error) |
| Integer | ⟺ | int | Supports big integers |
| Rational | ⟺ | fractions.Fraction() | |
| Float | ⟺ | float | |
| @(none) | ⟺ | None | |
| @(true) | ⟺ | True | |
| @(false) | ⟺ | False | |
| Atom | ⟵ | enum.Enum() | Name of Enum instance |
| Atom | ⟷ | String | Except the above reserved three atoms |
| String | ⟶ | String | |
| #(Term) | ⟶ | String | stringify using write_canonical/1 if not atomic |
| prolog(Term) | ⟶ | janus.Term() | Represent any Prolog term |
| Term | ⟵ | janus.Term() | |
| List | ⟶ | List | |
| List | ⟵ | Sequence | |
| List | ⟵ | Iterator | Note that a Generator is an Iterator |
| py_set(List) | ⟺ | Set | |
| -(a,b, ... ) | ⟺ | (a,b, ... ) | Python Tuples |
| Dict | ⟺ | Dict | |
| {k:v, ...} | ⟹ | Dict | Compatibility (see above) |
| py({k:v, ...}) | ⟹ | Dict | Compatibility (see above) |
| eval(Term) | ⟹ | Object | Evaluate Term as first argument of py_call/2 |
py_obj blob | ⟺ | Object | Used 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. Currently the mapping rational numbers uses an intermediate decimal string and is therefore relatively slow. Mapping from Python to Prolog relies on the ((_)_str__)() method of the instance returning +/-<num>/<den> where <num> and <den> are decimal numbers.
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. Internally, janus.Term()
is used to represent Prolog exeptions that are raised during the
execution of
janus.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.
-