Web Prolog manual

This manual describes the Web Prolog language and APIs implemented by the current demonstrator. It should be read as a snapshot of a design in progress, not as a final language specification: terminology, predicate interfaces, and behaviour are still tentative and may change as the implementation evolves.

The classification shown beside each entry identifies the minimum public node profile in which the predicate is available, or another relevant execution context. ISOBASE provides general stateless Prolog calls, ISOTOPE adds persistent toplevel sessions, and ACTOR adds the full stateful actor-messaging model. The profiles are cumulative, so an entry marked isotope is also available in ACTOR. The classification concerns the client language, not predicates used internally to implement a profile. Entries additionally marked owner only are reserved for code running with node-owner authority and are not available to ordinary client code.

This document reproduces the book's manual appendix in HTML form. Each predicate entry carries an HTML anchor using its predicate indicator so that entries can be linked directly.

Contents

Predicates for programming with core actors

Predicate: self/1
actor
self(-Pid) is det.

Binds Pid to the process identifier of the calling process.

Note: A pid is an actor address whose canonical global form is Id@Node, where Id is assigned by Node. This ordinary Prolog compound is part of the language contract: programs may copy, store, construct, decompose, compare, and serialise it. A shell may omit @Node for a pid on the shell's own node, but this is only a local abbreviation. Constructing a pid does not create an actor, confirm that it is live, or grant access to it; an operation reaches an actor only when the pair designates that actor and the node authorises the operation. Arithmetic on a numeric Id has no defined actor-level meaning. Browser runtimes reserve localhost as the local-node designator. Worker actors are therefore presented as, for example, 2159438818@localhost, and the optional main-thread SWI-WASM engine is presented as main@localhost.

Predicate: spawn/1-3
actor
spawn(+Goal) is det.
spawn(+Goal, -Pid) is det.
spawn(+Goal, -Pid, +Options) is det.

Creates a new Web Prolog actor process running Goal. A principal subtree quota raises error(resource_error(actors), _). Lost contact during remote creation raises error(remote_spawn_failed(connection_closed), _); the remote outcome is unknown and retrying side effects needs duplicate suppression.

Valid options are:

Note: In spawn(+Goal,-Pid,+Options), the option monitor(true) installs monitoring as part of process creation. When the child terminates, the parent receives a message down(Pid,Ref,Reason) where Pid is the terminated actor, Reason is its exit reason, and Ref identifies the monitor instance. For monitoring created via monitor(true), the current implementation uses Ref = Pid.

Note: The semantics of link(true) are directional: if a parent spawns a child with linking enabled, termination of the parent causes linked children to be terminated. The link does not imply symmetric bidirectional exit propagation.

Note: It is possible to pass an arbitrary number of the src_* options to spawn/3, and possibly more than one instance of each variant. To ensure that clauses end up in a well-defined order, they are converted into Prolog source text before being loaded into the database. The order of clauses and directives in the resulting source text is determined by the order of the src_* options in the option list.

Predicate: actors/1
actor
actors(-Pids) is det.

Binds Pids to the list of actor pids visible from the current execution context. In ordinary public client execution, this means the current actor or toplevel together with any actors that have been spawned on behalf of the same client interaction. Actors belonging to other clients are not included.

Note: Outside public client execution, for example in node-owned runtime code or administrative code, actors/1 returns the pids of all active local actors on the node.

Predicate: monitor/2
actor
monitor(+PidOrName, -Ref) is det.

Installs a monitor on an actor the caller may send to and returns a fresh reference in Ref. References use secure randomness and are never reissued; knowing a reference does not authorize removal of another actor’s monitor. The first argument may be a pid or a registered local name. When the monitored process terminates, the monitoring process receives a message of the form down(Pid,Ref,Reason).

Note: monitor(true) in spawn/3 installs monitoring before the child can terminate, preserving its actual exit reason. A monitor installed after termination is discharged with down(Pid,Ref,no_process).

Reasons include true for success, false for failure, exception(E) for an uncaught exception, and an explicit exit term. Loss of remote observation produces connection_closed; it discharges the monitor without proving actor death, and reconnection does not restore it. At the monitor boundary, an SWI error(Formal,Context) preserves Formal but replaces Context with a variable. Undefined-procedure errors also omit private generated actor-module qualifications.

Predicate: demonitor/1-2
actor
demonitor(+Ref) is det.
demonitor(+Ref, +Options) is det.

Stops only a monitor installed by the calling actor and identified by Ref. This is idempotent. There is only one valid option:

Predicate: register/2
actor
register(+Name, +Pid) is det.

Registers an actor process under a name, where Name is an atom and Pid identifies the actor. The association between the name and the pid is removed when the process terminates.

Predicate: whereis/2
actor
whereis(+Name, -Pid) is det.

Binds Pid to the actor process associated with Name, or to undefined if no such registration exists.

Predicate: unregister/1
actor
unregister(+Name) is det.

Removes the association between the name and the process. The actor itself is not terminated. The operation is idempotent and succeeds without effect if Name is not registered.

Predicate: register_service/2
actor, owner only
register_service(+Name, +Pid) is det.

Publishes the live local actor identified by Pid under Name in the node's public service namespace. Name must be an atom, Pid must identify an actor on the publishing node, and there may be at most one published service with a given name on a node. If the name is already published, register_service/2 raises permission_error(register,service,Name), even when the existing entry denotes the same actor. Replacement is therefore explicit: the owner must first withdraw the old mapping.

The public service namespace is distinct from the ordinary registration namespace used by register/2; the same atom may occur in both without a collision. A qualified address Name@Node is resolved against the public service namespace of Node. whereis/2 consults only the ordinary namespace; owner-side code may inspect the service namespace with whereis_service/2.

Publication neither changes the actor's links nor places it under supervision. In particular, register_service/2 does not detach the actor from its parent. When the actor terminates, the node controller removes the service mapping atomically, so a published name never remains bound to a dead pid. A supervisor that starts a replacement actor must publish that actor again under the stable name.

Only code executing with node-owner authority may call this predicate. A call by any other principal raises permission_error(register,service,Name). A non-atom Name raises type_error(atom,Name); a Pid that does not identify a live actor raises existence_error(process,Pid); and an attempt to publish an actor on another node raises permission_error(register,service,Pid).

Predicate: whereis_service/2
actor, owner only
whereis_service(+Name, -Pid) is det.

Binds Pid to the live local actor published as Name, or to undefined if no such service is published. This predicate inspects only the public service namespace.

Only code executing with node-owner authority may call it; other callers receive permission_error(access,actor_service_registry,whereis_service(Name,Pid)). A non-atom Name raises type_error(atom,Name).

Predicate: unregister_service/1
actor, owner only
unregister_service(+Name) is det.

Withdraws Name from the node's public service namespace. This removes only the name: it neither terminates nor otherwise changes the actor that the name denoted. The operation is idempotent and succeeds without effect when no such service is published.

Only code executing with node-owner authority may call this predicate; other callers receive permission_error(unregister,service,Name). A non-atom name raises type_error(atom,Name).

Predicate: exit/1
actor
exit(+Reason) is det.

Terminates the calling process with Reason.

Predicate: exit/2
actor
exit(+Pid, +Reason) is det.

Terminates an actor in the caller’s ownership tree, identified by Pid, with Reason. A client targeting another tree receives error(permission_error(exit, actor, Pid), _). Raw host thread ids and aliases are never actor termination targets. For remote actors, the runtime routes this request through the remote node. Termination commits when the first exit reason is accepted; later exit and abort signals have no effect.

Predicate: !/2, send/2-3
actor
+PidOrName ! +Message is det.
send(+PidOrName, +Message) is det.
send(+PidOrName, +Message, +Options) is det.

Sends Message to the mailbox of the process identified as PidOrName. PidOrName may be a local pid, a local registered name, a global pid of the form Id@Node, or a published service address of the form Name@Node. A global pid may be a value returned by the runtime or a term constructed directly from a known identifier and node; the two are equivalent. Qualified service addresses are resolved only through the destination node's live service registry. If such a service is absent or the sender is not authorised to use it, the send succeeds without delivery and does not reveal which condition applied. By contrast, an unknown local registered name raises existence_error(actor_name,Name); a send to an unknown pid succeeds without delivery. Valid options for send/3 are:

Portable actor application messages are acyclic ordinary Prolog terms. Atoms, strings, numbers, variables, lists, and compound terms are portable; variables arrive as fresh variables. Attributed variables, streams, and other non-text blob values must be encoded explicitly by the application. The demonstrator validates this subset whenever serialization is required, and writes such terms as canonical text: quoted, without operator syntax, portray hooks or numbervars, and with explicit variable names. A double-quoted literal denotes a string in every profile: goals, options, answers, input and actor source are read with double_quotes set to string, whatever the host's default. Native local delivery may happen to carry additional host terms, but programs using them are outside the placement-independent contract.

Predicate: cancel/1
actor
cancel(+ID) is det.

Tries to cancel the sending of all delayed messages with the specified ID. This is best-effort only, since a message may already have been sent by the time the call is made.

Predicate: output/1-2
actor
output(+Data) is det.
output(+Data, +Options) is det.

Sends a message output(Pid,Data) to the target process. Pid is the pid of the current process. Valid option:

Note that this is just a convenience predicate. Any actor may use !/2 to send any term to any process to which it has a pid.

Predicate: input/2-3
actor
input(+Prompt, -Data) is det.
input(+Prompt, -Data, +Options) is det.

Sends a message prompt(Pid,Prompt) to the target process and waits for its input. Prompt may be any Prolog term. Pid is the pid of the current process. Data will be bound to the term that the target process sends using respond/2. Valid option:

Predicate: respond/2
actor
respond(+Pid, +Input) is det.

Sends Input to the process identified by Pid as a response to a prompt(Pid,Prompt) message.

Predicate: receive/1-2
actor
receive(+Clauses) is nondet.
receive(+Clauses, +Options) is nondet.

Waits for, selects, and consumes one message from the calling process's mailbox. A call is single-message, but not necessarily single-solution. During one invocation it selects and consumes at most one message. Messages are considered in arrival order, and each message is tested against the receive clauses in textual order. The first message accepted by a clause is removed from the mailbox. This selection is committed: backtracking through the invocation never selects another message or another clause.

The selected clause body is ordinary Prolog code. The call as a whole therefore has the determinism of the fired body: a body may fail, succeed once, throw an exception, or yield several solutions. Choice points left by the body remain available, but they enumerate solutions of that same body; they do not inspect the mailbox again. The selected message remains consumed if the body fails or throws, and is not restored on backtracking. Thus the nondet declaration concerns the possible number of logical solutions, not the number of messages consumed by one invocation. For example, after one foo message has arrived, receive({foo -> member(X, [a,b])}) consumes that message once but can yield both X = a and X = b.

Clauses has the following form:

{  Pattern1 [if Guard1] ->
         Body1 ;
   ...
   PatternN [if GuardN] ->
         BodyN
}

A clause accepts a message if its pattern matches the message and its optional guard succeeds. Matching is one-sided: the pattern must subsume the message, so a pattern never binds variables that occur in the message. A guard is evaluated for its first solution only, as if by once/1, and should be free of side effects. Bindings from the pattern and guard are in scope in the body. If a guard fails or raises an ordinary exception, that clause does not accept the message. Control exceptions (abort, termination, enforced limits) propagate out of receive/1-2, and the message being examined stays in the mailbox. A guard that checks a correlation reference or a pid should test it with == rather than bind it.

Messages accepted by no clause are deferred: they remain in the mailbox, without any change in their contents or relative order, and are available to later receive calls. receive({}) accepts no message and waits, subject to Options. Valid options:

Predicate: flush/0
actor
flush is det.

Removes all messages currently pending in the mailbox of the calling process. Each removed message is rendered through the actor terminal-output path as a line of the form Shell got Message, where Message is the full Prolog term.

Note: flush/0 is primarily a shell-level inspection utility. It does not wait for future messages: once the mailbox is empty at the time of the call, it succeeds immediately.

Predicate: listing/0-1
isotope
listing is det.
listing(+What) is det.

listing/0 lists the content of the private database of the current actor process through the terminal-output path. Imported predicates and the injected I/O wrapper predicates are omitted.

listing/1 lists the predicates or clauses in the current process's private database selected by What, following the conventional Prolog meaning of listing/1. What may be a predicate indicator (Name/Arity or Name//Arity), a callable head pattern, a clause reference, or a list of such specifications. It does not provide access to another actor's private database.

Predicates for programming with toplevel actors

Predicate: toplevel_spawn/1-2
actor
toplevel_spawn(-Pid) is det.
toplevel_spawn(-Pid, +Options) is det.

Spawns a toplevel actor and binds Pid to its pid. All options accepted by spawn/3 are also accepted by toplevel_spawn/2. In addition, toplevel_spawn/2 accepts the following options:

Both finite lifecycle limits must be positive numbers of seconds. A public client may request tighter values, but cannot weaken the node owner's ceilings. These limits are distinct from an ISOTOPE session HTTP request's timeout, which only bounds how long that request waits for the next queued event and does not abort the goal or terminate the session.

Predicate: toplevel_call/2-3
actor
toplevel_call(+Pid, +Goal) is det.
toplevel_call(+Pid, +Goal, +Options) is det.

Asks the toplevel Pid for solutions to Goal. Valid options are:

Variables in Goal are not bound directly in the caller. Instead, solutions and other kinds of output are returned in the form of answer messages delivered to the mailbox of the target process:

A toplevel serves one controlling client at a time, and each call starts afresh: when it accepts Goal, it discards any toplevel_next/1-2, toplevel_stop/1 or input left over from an earlier query, that is, sent before the call; one sent after the call is kept. If the goal raises an exception after a finite limit has already collected some solutions, those solutions are delivered first as success(Pid, Data, true), and the error answers the following toplevel_next/1-2. A toplevel_stop/1 in that state discards the error.

Answers are plain terms. A solution that still carries constraints, such as those left by dif/2, freeze/2 or CLP(FD), cannot be represented in an answer: printing it would drop the constraints. The toplevel then reports error(Pid, error(representation_error(constraints), _)) instead of the page, and the query ends. This holds whether the client is local or remote. A goal that needs such answers should bind the constrained variables, for example by labelling, or return the constraints as ordinary terms.

Predicate: toplevel_next/1-2
actor
toplevel_next(+Pid) is det.
toplevel_next(+Pid, +Options) is det.

Asks toplevel Pid for more solutions. Valid options:

The messages delivered to the target mailbox are the same as for toplevel_call/2-3.

Predicate: toplevel_stop/1
actor
toplevel_stop(+Pid) is det.

Asks toplevel Pid to stop searching for more solutions.

Predicate: toplevel_abort/1
actor
toplevel_abort(+Pid) is det.

Tells the local toplevel Pid to abort the currently running goal. Abort runs supported cleanup, bypasses recovery in client catch/3, and returns a persistent session to PTCP state s1 without terminating the actor. A session(false) toplevel terminates instead. An abort in s1 leaves a persistent session idle, one in s3 abandons the suspended solutions, and one that arrives after termination has been committed is ignored. Every abort that reaches a live toplevel, including one in s1, is acknowledged: the toplevel sends abort(Pid) to the client of its most recent call (or, before any call, to its spawn target), after any answers the aborted query had already sent. A client that waits for abort(Pid) before its next call therefore knows that every answer received before it belongs to the aborted query. An unknown or non-local pid has no effect.

Predicate: toplevel_halt/1-2
actor
toplevel_halt(+Pid) is det.
toplevel_halt(+Pid, -Reply) is det.

Terminates toplevel actor Pid from any protocol state. The one-argument form requests termination through the actor runtime and returns without waiting for confirmation. The two-argument form installs a private monitor and waits for its notification. Observed termination or no_process yields Reply = true. Loss of remote observation yields Reply = error(connection_closed), leaving termination unconfirmed. Halt is an untrappable termination signal.

Note: The private monitor used by toplevel_halt/2 is distinct from any existing monitor. If the toplevel was spawned with monitor(true), the caller still receives its original down(Pid, Pid, true) notification.

Predicates for programming with server actors

Predicate: server_spawn/3-4
actor
server_spawn(+Pred, +State, -Pid) is det.
server_spawn(+Pred, +State, -Pid, +Options) is det.

Spawns a generic server actor using callback predicate Pred/4 and initial state State. The callback receives (Request, OldState, Response, NewState).

All options are forwarded to spawn/3 except:

Predicate: server_request/3-4
actor
server_request(+To, +Request, -Response) is det.
server_request(+To, +Request, -Response, +Options) is det.

Makes a synchronous request-response call to the server To, where To may be a pid or a registered local name. server_request/4 accepts the options of receive/2, for example timeout(+Seconds).

Monitoring is installed automatically so the call fails fast if the server terminates before replying.

Predicate: server_promise/3-4
actor
server_promise(+To, +Request, -Ref) is det.
server_promise(+To, +Request, -Ref, -MonRef) is det.

Sends Request to the server To and returns a correlation reference Ref. The reply must later be collected with server_yield/2-4.

The four-argument variant additionally installs a monitor and returns its reference in MonRef.

Predicate: server_yield/2-4
actor
server_yield(+Ref, -Response) is det.
server_yield(+Ref, -Response, +Options) is det.
server_yield(+Ref, +MonRef, -Response, +Options) is det.

Waits for the response matching Ref. The three-argument variant accepts the options of receive/2.

The four-argument variant uses MonRef to detect server termination and throws server_down(Reason) if the server dies before replying. When the wait finishes, fails, or throws, it removes the monitor and flushes pending notifications for that reference. This includes timeout paths. Alternatives supplied by on_timeout/1 remain available; cleanup occurs when the call finishes.

Predicate: server_upgrade/2-3
actor
server_upgrade(+To, +Pred) is det.
server_upgrade(+To, +Pred, +Options) is det.

Replaces the callback predicate of the running server To without disturbing its current state. Pred must denote a callback predicate of arity four.

The two-argument form transfers no code and requires the callback to be present already in the server's private database. The three-argument form loads callback source using src_text/1, src_list/1, src_predicates/1, or src_uri/1.

The operation replies only after the callback has been loaded and validated. It preserves the current state value and performs no state migration. If installation fails, server_upgrade/2-3 rethrows the reported error and the state is unchanged. Source changes made in the server's private database before the error are not rolled back.

Predicate: server_halt/2
actor
server_halt(+To, -Reply) is det.

Asks the server To to stop gracefully and binds Reply to its acknowledgement.

A fresh correlation reference prevents unrelated acknowledgements from satisfying the request. A private monitor is installed before sending; if the server dies before acknowledging, the call throws server_down(Reason). The private monitor and its pending notifications are removed on completion, failure, or exception. Existing monitors are unaffected.

Predicates for programming with statechart actors

Predicate: statechart_spawn/2
actor
statechart_spawn(-Pid, +Options) is det.

Spawns a statechart actor and binds Pid to its pid.

statechart_spawn/2 requires exactly one source option:

In addition, statechart_spawn/2 accepts:

trace(true) (the default) generates trace events; trace(false) suppresses them. At most one trace/1 option is accepted: duplicates raise permission_error(duplicate, statechart_option, trace). The Logger's SXML trace filter controls the visibility of generated events; tutorial diagrams consume those events for animation.

All remaining options are passed through to spawn/3.

src_list/1 and src_predicates/1 supply supplemental Prolog source for the statechart's private module. They do not count as the required XML source.

Predicate: statechart_halt/2-3
actor
statechart_halt(+Pid, -Reply) is det.
statechart_halt(+Pid, -Reply, +Timeout) is det.

Asks the statechart actor Pid to halt gracefully, running the exit actions of its active states, and waits for an acknowledgement in Reply. The two-argument form waits indefinitely.

The three-argument form waits at most Timeout seconds. If the actor does not reply in time, it is killed and Reply becomes killed.

Predicate: raise/1
statechart builtin
raise(+Event) is det.

Enqueues Event on the internal event queue of the current statechart interpreter.

Important: raise/1 is only meaningful inside executable statechart content such as <onentry>, <onexit>, and <go>. The event is handled after the current executable content and before a new external message. Datamodel source is loaded before the event queue is initialized.

Predicate: in/1
statechart builtin
in(+Id) is semidet.

Succeeds if the state identified by Id belongs to the current active configuration of the statechart interpreter.

Important: in/1 is only meaningful inside statechart guards or executable statechart content such as <onentry>, <onexit>, and <go>.

Predicates for programming with supervisor actors

Predicate: supervisor_spawn/2-3
actor
supervisor_spawn(+ChildSpecs, -Pid) is det.
supervisor_spawn(+ChildSpecs, -Pid, +Options) is det.

Spawns a supervisor actor and starts its children. Supported options are:

Other options are passed through to spawn/3.

Child specifications take the form child(Id, ChildOptions). Child options are:

Predicate: supervisor_spawn_child/3
actor
supervisor_spawn_child(+Pid, +ChildSpec, -Reply) is det.

Dynamically adds and starts one child. On success, Reply is ok. If a child with the same Id is already present, it is error(already_present). If startup fails, it is error(start_failed).

Predicate: supervisor_terminate_child/3
actor
supervisor_terminate_child(+Pid, +Id, -Reply) is det.

Stops child Id but keeps its specification. Reply is ok or error(not_found).

Predicate: supervisor_delete_child/3
actor
supervisor_delete_child(+Pid, +Id, -Reply) is det.

Removes a non-running child specification. Reply is ok, error(running), or error(not_found).

Predicate: supervisor_respawn_child/3
actor
supervisor_respawn_child(+Pid, +Id, -Reply) is det.

Restarts a previously terminated child from its stored specification. Reply is either ok(NewPid), error(running), error(not_found), or error(start_failed).

Predicate: supervisor_which_children/2
actor
supervisor_which_children(+Pid, -Children) is det.

Returns a list of:

info(Id, Pid, Type, Restart)

where Pid may be undefined for stopped children.

Predicate: supervisor_count_children/2
actor
supervisor_count_children(+Pid, -Counts) is det.

Returns:

[specs-N, active-N, supervisors-N, workers-N]
Predicate: supervisor_halt/1
actor
supervisor_halt(+Pid) is det.

Stops the supervisor and shuts down children in reverse start order.

Note on synchronous supervisor calls

The dynamic/query API above uses monitored synchronous calls and may throw:

Actor-based predicate generics

Predicate: parallel/1
actor
parallel(+Goals) is semidet.

Runs the proper list of independent goals Goals concurrently, using one monitored worker actor per goal. The call succeeds when every goal has produced its first solution and returns the resulting variable bindings. parallel([]) succeeds immediately. Further solutions are not enumerated on backtracking.

If any goal fails, the remaining workers are terminated and the call fails. If any goal throws an exception, the remaining workers are terminated and the exception is rethrown. Result and monitor messages belonging to the workers are removed before the predicate returns, fails, or throws.

The goals must not depend on bindings or side effects produced by sibling goals. Actor creation and message copying add overhead, and the one-worker-per-goal model gives large goal lists a correspondingly large resource footprint.

A non-list Goals raises type_error(list, Goals). An element that is not callable raises the corresponding callable type error from its worker, which is propagated to the caller.

Predicate: first_solution/2-3
actor
first_solution(?Solution, +Goals) is semidet.
first_solution(?Solution, +Goals, +Options) is semidet.

Runs the proper list of alternative goals Goals concurrently in monitored worker actors and unifies Solution with the result produced by the first solver to succeed. Once a winner has been selected, all remaining workers are terminated and their result and monitor messages are removed. The predicate does not enumerate later solutions on backtracking, and an empty goal list fails.

The two-argument form continues after an individual solver fails and stops on the first exception. The three-argument form accepts:

If all alternatives are removed under a continue policy, the predicate fails. Goals should not depend on side effects produced by sibling solvers.

A non-list Goals or Options raises type_error(list, Term). An action other than stop or continue raises type_error(oneof([stop,continue]), Action). An unknown option raises domain_error(first_solution_option, Option).

Predicates for remote Prolog-style calls

Predicate: rpc/2-3
isobase
rpc(+URI, +Goal) is nondet.
rpc(+URI, +Goal, +Options) is nondet.

Executes a copy of Goal through the stateless /call endpoint of the node identified by URI, then unifies the local goal with each returned solution on backtracking. This remains a stateless call even when the destination is an ACTOR node: actor-only predicates such as self/1, spawn/1-3, and receive/1-2 are not available through rpc/2-3.

The first argument alone selects the execution node. localhost means the node on which rpc/2-3 is running. Source-loading options supply source for the call's temporary private database and do not change that target. For example, rpc('https://n2.example',Goal,[src_uri('https://n3.example')]) executes Goal on n2.example using source fetched from n3.example. All conforming native and browser runtimes accept:

Predicate: promise/3-4
isobase
promise(+URI, +Goal, -Ref) is det.
promise(+URI, +Goal, -Ref, +Options) is det.

Starts one asynchronous stateless call to node URI with Goal and returns a local promise reference in Ref. As with rpc/2-3, the first argument selects the execution node and localhost denotes the current node. Source-loading options populate the promised call's temporary private database; they do not change its execution node. It accepts the same limit/1, once/1, timeout/1, http_timeout/1, and src_*/1 options as rpc/3, together with:

The reference returned in Ref can later be used by yield/2-3 to collect the single answer term. Programs must not infer meaning from its digits or construct references themselves.

Predicate: yield/2-3
isobase
yield(+Ref, ?Answer) is det.
yield(+Ref, ?Answer, +Options) is det.

Waits for the answer term from a previous call to promise/3-4. The reference is local to the runtime that created it. The answer is one of success(Data,More), failure, or error(Error), as returned by the stateless call endpoint. Valid options are:

A timeout does not cancel or consume the promise; a later call with the same reference may collect an answer that arrives afterward. If on_timeout/1 is omitted, the timeout path succeeds.

Predicate: runtime_property/1
isobase
runtime_property(?Property) is nondet.

Enumerates properties of the host runtime. This predicate reports capabilities; it does not alter the Web Prolog profile or the semantics of the predicates above. Defined properties are:

Native nodes are persistent and inbound-addressable and use native threads with hard termination, but have no DOM. Worker SWI-WASM actors have Web-Worker isolation and hard termination but share the page's lifetime, are not inbound-addressable, and have no DOM. The optional main-thread SWI-WASM engine has DOM access but cooperative engine isolation and no hard termination; it too shares the page's lifetime and initiates rather than accepts remote connections.

ISO predicates and related constructs

The following ISO Prolog predicates and related constructs are available to clients of a Web Prolog node. Predicates that require direct stream or file access, module loading, runtime reflection, or parser state mutation are excluded by the sandbox.

Control Constructs

true/0, fail/0, call/1-8, !/0, (,)/2, (;)/2, (->)/2, (\+)/1, catch/3, throw/1

Directives

dynamic/1, multifile/1, discontiguous/1

Term Unification

(=)/2, (\=)/2, unify_with_occurs_check/2

Arithmetic Evaluation and Comparison

is/2, (=:=)/2, (=\=)/2, (<)/2, (>)/2, (>=)/2, (=<)/2

Arithmetic Functions

(+)/1-2, (-)/1-2, (*)/2, (//)/2, (/)/2, rem/2, mod/2, abs/1, sign/1, float_integer_part/1, float_fractional_part/1, float/1, truncate/1, round/1, ceiling/1, floor/1, max/2, min/2, (**)/2, sin/1, cos/1, atan/1, atan2/2, exp/1, log/1, sqrt/1, (>>)/2, (<<)/2, (/\)/2, (\/)/2, (\)/1, xor/2, pi/0

Term Comparison

(@<)/2, (@>)/2, (@>=)/2, (@=<)/2, compare/3

Type Testing

var/1, nonvar/1, atom/1, number/1, integer/1, float/1, compound/1, atomic/1, callable/1, ground/1

Term Creation and Decomposition

functor/3, arg/3, (=..)/2, copy_term/2

Clause Retrieval

clause/2

Clause Creation and Destruction

asserta/1, assertz/1, retract/1, abolish/1

All-Solutions

findall/3, bagof/3, setof/3

Actor I/O (Overrides)

The ambient stream I/O predicates of ISO Prolog are blacklisted. In their place, the actor runtime prelude injects local overrides that route output through the actor messaging layer:

nl/0, write/1, writeq/1, write_term/2, writeln/1, write_canonical/1, print/1, display/1, format/1-2

read/1 uses the session prompt protocol. time/1 reports timing through the output channel and checks its nested goal against the active profile and sandbox.

format/1-2 rejects the goal-executing ~@ directive, including numeric and colon-modified forms such as ~1@, ~:@, and ~*:@, with permission_error(use, format_specifier, '~@'). Escaped ~~@ produces literal text.

Atomic Term Processing

atom_length/2, atom_concat/3, atom_chars/2, atom_codes/2, sub_atom/5, char_code/2, number_chars/2, number_codes/2

Node introspection

Predicate: node_setting/2
all public profiles
node_setting(?Key, ?Value) is nondet.

Enumerates publicly visible settings of the node servicing the request. With Key bound, succeeds for its visible current value. Unknown or unavailable keys fail. Credentials, principal policies, and shared-database source are not exposed.

API-specific keys are visible only when their corresponding built-in family is enabled for the node's profile. This predicate reads settings; it does not modify them.

HTTP and WebSocket conventions

These wire conventions complement the predicate API above and the book's Appendix D.

Results and source loading

Remote execution-time exhaustion is reported as error(resource_error(time), _); memory exhaustion as error(resource_error(space), _). RPC clients propagate these exceptions without a wrapper. The context is elided in normal display. A client transport timeout is distinct and does not establish that the remote computation has stopped.

In JSON success events, data is a list of binding objects whose values are Prolog-text strings: for example, {"X":"42"}. Default JSON query formatting replaces an explicit template with the visible named query variables. HTTP format=prolog returns a Prolog answer term and honors the template. WebSocket format(prolog) honors the template but retains a JSON envelope with Prolog-term strings in its data array. A down event's reason is Prolog term text; numeric monitor references are JSON numbers.

Supply source through spawn options. HTTP /toplevel_call still accepts changed, nonempty src_text for compatibility; empty or unchanged source does not reload. WebSocket toplevel_call rejects a src_text field even when empty. Its canonical options string accepts only template/1, offset/1, limit/1, once/1, and format/1. Defaults are the goal, 0, no solution-count limit, false, and json, respectively. Goal and options are parsed together. A WebSocket toplevel_next frame may include a JSON integer limit; omission inherits the current limit.

HTTP sessions force session(true); WebSocket toplevel spawn defaults to session(false). HTTP polling retrieves one queued event without advancing the solution sequence. Its timeout does not abort the goal. An HTTP abort replies only after the toplevel has acknowledged it, with an event of type abort. Every session request's response carries a Web-Prolog-Seq header numbering the event it returned. A client that did not receive a response may repeat the request with a Web-Prolog-Ack header holding the last number it did receive; if the lost response is the session's latest event, the node sends it again instead of running the command a second time. A session's former owner that addresses it after it has ended or been reclaimed receives an error whose code field is session_lost. The transport's statechart_trace setting defaults to false and is stored and acknowledged, but the current delivery code does not consult it to suppress traces. Use the statechart's trace/1 option to control generation.

Browser transport extensions

{"command":"transport_hello","version":1,
 "browser_pids":true,"io_ack":true}

The node answers with type:"transport_welcome", protocol:"web_prolog_browser_actor", version:1, and both capability flags set to true. Flags in the welcome advertise support; each extension is enabled only when requested in the hello.

With browser_pids enabled, qualified browser-local pids embedded in goals, templates, and messages receive connection-scoped return routes. Bare numbers, atoms, and source strings remain data. Replies arrive as:

{"type":"actor_message","target":"2159438818@localhost",
 "message":"reply(ok)"}

With io_ack enabled, terminal output arrives inside an acknowledgement request:

{"type":"io_request","request_id":"opaque-reference",
 "event":{"type":"output","pid":123,"data":"hello"}}

After accepting the output, reply on the same connection:

{"command":"browser_io_reply","request_id":"opaque-reference",
 "status":"ok"}

The alternative status is error. The actor waits for acceptance; an error, connection closure, or a 30-second acknowledgement timeout raises an I/O error. Late replies are discarded. This acknowledges acceptance, not browser painting. Prompts and query answers retain their ordinary event forms. Without this extension, output arrives directly as an output event.

WebSocket-created actors have a connection lifecycle monitor in addition to any explicit client monitor. Its down event carries a node-generated reference. Closing the connection terminates its actors and revokes browser return routes.