Did you know ... | Search Documentation: |
Calling Prolog from JavaScript |
The Prolog
class provides several methods for calling
Prolog from JavaScript.
String
and returns
true
or false
. This simple calling pattern is
intended for trivial goals such as setting a Prolog flag. For example,
the call below limits the Prolog stacks to 10Mb.
Prolog.call("set_prolog_flag(stack_limit, 10 000 000)");
String
, optionally binding
Prolog variables embedded in Goal from properties of the Object
Input. The returned object is an instance of class Query
.
This instance can be used as a JavaScript iterator. The value
returned in each iteration is an Object
with properties for
each variable in Goal that is not in Input and
does not start with an underscore. For example, we can iterate over the
members of a list like below. Further details on class Query
are provided in section
13.2.1. The translation of data between Prolog and JavaScript is
described in section
13.2.2.
for(let r of Prolog.query("member(Elem,List)", {List: ["aap", "noot", "mies"]})) { console.log(r.Elem); }
This interface is also practical for calling (fast) Prolog predicates
to compute a single answer from an input using the Query.once()
method. Assuming a Prolog predicate fib/2 that computes the nth Fibonacci
number, we can call this using the code below. Note that if the fib/2
fails or raises an exception the object returned by Query.once()
does not contain the
Out
key and thus our function returns undefined
.
function fib(in, out) { return Prolog.query("fib(In,Out)", {In:in}).once().Out; }
The .query()
method is indented for fast queries
that do not require the yield mechanism, i.e., the execution
should not require asynchronous operations and the browser is not
responsive during the execution.
.query()
. For each answer, OnAnswer
is a
Function
that is called with a Object
that
holds the bindings for the output arguments of Goal.
The returned Promise
is resolved when the query
completes. The value passed to the .then()
method of
the Promise
is the number of answers if OnAnswer
is provided or an Array
of answers if OnAnswer
is omitted. If Goal raises an exception the Promise
is rejected.
Multiple calls to Prolog can be activated at any time. Prolog
processes such queries in LIFO (Last In, First Out)
mode. If queries need to be processed sequentially use JavaScript await
or the Promise.finally()
method to wait for
completion.
The method Prolog.query()
returns an instance of the JavaScript class Query
that may
be used to explore the solutions of the query. The Query
class implements the JavaScript iterator protocol.
done
and value
. If exception
handling is enabled it returns an object
{done
:true
, error
:true
,
message
:String}..value
of the object returned by .next()
on success and the
complete object on failure or error. In addition, on a logical result
(no error), a field
success
is added with a boolean value. Thus, the return
value may contain these keys:
success
key is set to true
.success
:false}error
:true, message
:String}
JavaScript and Prolog are both dynamically typed languages. The WASM module defines a faithful translation between JavaScript data and Prolog data that aims at completeness as well as keeping the data representation clean in the common cases. We describe the translation in two descriptions because round tripping does not always result in the original object.
This section describes how data from JavaScript is translated into Prolog. The interface is primarily designed for passing JavaScript data as typically used to a natural Prolog representation. In addition a number of classes are provided to create Prolog specific data structures such as strings (as opposed to atoms), variables, compound terms, etc.
new Prolog.String(text)
to create a Prolog string. See below.true
or false
.undefined
.null
.$
:Typev
holds the text. May be
created using new Prolog.string(text)
. May be created using new
Prolog.String(text)
.n
and d
represent the numerator and denominator. For example,
to represent 1r3
, use {$
:"r",
n
:1, d
:3}. May be created using new
Prolog.Rational(n, d)
, where n and d can be
JavaScript numbers or big integers.point(1,2)
is constructed using
{$
:"t", point
:[1,2]}. May be created using new
Prolog.Compound(functor, args)
v
is present this
identifies the variable. Two variables processed in the same translation
with the same identifier represent the same Prolog variable. If the v
key is omitted the variable will be unique. May be created using new
Prolog.Var(id)
.Array
we only need
this typed object to create a partial list. The v
key contains the “normal” elements and the key tail
contains the tail of the list. May be created using new
Prolog.List(array, tail)
.Object
dict
.
Note that JavaScript object keys are always strings and (thus) all dict
keys are atoms. This, {1:"one"} is translated into
_{'1': one}
.ArrayBuffer
are translated into a Prolog
string that consists of characters in the range 0 ... 255.Object
<js_Class(id)>
. The
Prolog interface allows for passing the objects back and calling methods
on them. See section
13.3.
Most of the translation from Prolog data to JavaScript is the reverse
of the translation described in section
13.2.2.1. In some cases however reverse translation is ambiguous.
For example, both
42
and 42n
(a JavaScript BigInt
)
translate to a simple Prolog integer. The other way around, as
JavaScript
Number
is a float, both Prolog 42
and 42.0
translate to 42
in JavaScript.
Prolog.Variable
instance where
the identifier is a unique number of each unique variable.Number
when possible or
BigInt
otherwise. Currently JavaScript Number
can represent integers upto 2^53 precisely.Prolog.Rational
instance.Number
.String
.Prolog.String
instance.Array
,
otherwise create a JavaScript Prolog.List
instance.Prolog.Compound
instance.Object
with the same keys. If the
dict has a non-var tag, add a $tag
property.