Introduction

QuLog is a flexibly typed hybrid logic, functional, string processing language with an imperative action language sitting on top. It is higher order in that named relations, functions and actions can be passed as arguments and returned as values. The declarative kernel was developed to complement our robotic agent programming language TeleoR, to provide a TeleoR programmed robotic agent with its reasoning capability. TeleoR was inspired by and builds upon Nilsson's Teleo-Reactive Procedures language. The relations, functions and actions are all defined by sequences of conditional and unconditional rules. A special class of dynamic relations are defined solely by facts. Only action rules can call primitive actions of the language, such as file I/O, thread creation, inter-process communication, and updates of the dynamic relations. More generally action rules can be used to program multi-threaded communicating agent behaviour. QuLog's static relation and function definitions then comprise the agent's knowledge. The dynamic facts record its changing beliefs. It is a fully integrated language in that function calls can appear as or inside arguments to relation and action calls, and relational queries can be used as guards of function and action rules rules. It has sets as a separate data type from lists with convertors for mapping between the two data types. Both can be created using Term::Query comprehension expressions. Sets are manipulated using union, intersection and difference operators. Lists are manipulated as in Prolog but also using non-deterministic pattern matching. Similar pattern matching is used for string processing as a precursor to DCG parsing. An 'in' primitive can be used to access elements of sets, lists and characters in strings. A QuLog agent application typically comprises a set of independent multi-threaded agent processes each of which has an its own knowledge and beliefs. The beliefs may be shared, but only if explicitly communicated or placed in a communal repository. Each agent thread has a name, which is unique within the agent, and executes some action call. It can atomically query the agent's current belief facts using its fixed knowledge. It can also atomically update these facts using remember and forget actions. Changing the shared memory of dynamic facts is the main way that an agent's threads communicate. However a thread can also asynchronously communicate with other internal agent threads using send and receive actions, with receiver and sender identified by their unique thread names. Each thread has one message queue that only it can access. A sent message, which is a QuLog data term, is placed at the back of the destination thread's message queue. A receive primitive allows a thread to search the message queue from front to back for a message satisfying some test. The same message send action can be used to send a copy of a message to a thread in another agent process. In this case the destination thread must be identified by a term that gives not only the thread name, but the agent process name. If the agent is running on a host different from the one on which the sending agent process is running, the different host must also be identified using a destination address of the form ThreadName:AgentName@HostName. Such inter-agent communication routes the message via a Pedro communication server. Pedro is companion free software downloadable from: https://staff.itee.uq.edu.au/pjr/HomePages/PedroHome.html. When an agent is launched it typically connects and registers its name, which must be unique for the host on which it is running, with a Pedro server. The server may be located anywhere on the internet of hosts reachable from the agent's host machine. A message sent to a thread in another QuLog process, which has registered with the same Pedro server, is routed to the other QuLog process which puts it at the back of the message buffer for the named thread. It is put into a default message handling thread if the destination address for the message has the form AgentName@HostName, with no thread name. Pedro also supports message routing of unaddressed notifications using lodged subscriptions. This allows multi-casting of a message to any agent that has lodged a subscription with Pedro that covers the message term. A QuLog application can also receive and send MQTT notifications routed via an MQTT publish/subscribe server. Debugging is done by putting a watch on any number of relations, functions and actions. This invisibly transforms their code to display each call, the input and output bindings of the unification or match of the call with each rule that can be used, and optionally the instantiated body of the rule before it is used. An unwatch command reverses the code transformation.