SWISH: SWI-Prolog for Sharing
Recently, we see a new type of interfaces for programmers based on web technology. For example, JSFiddle, IPython Notebook and R-studio. Web technology enables cloud-based solutions, embedding in tutorial web pages, attractive rendering of results, web-scale cooperative development, etc. This article describes SWISH, a web front-end for Prolog. A public website exposes SWI-Prolog using SWISH, which is used to run small Prolog programs for demonstration, experimentation and education. We connected SWISH to the ClioPatria semantic web toolkit, where it allows for collaborative development of programs and queries related to a dataset as well as performing maintenance tasks on the running server and we embedded SWISH in the Learn Prolog Now! online Prolog book.
This article is organised as follows. Section 2 describes related work, which in our case are the systems that have inspired us. Section 3 describes the architecture and components of SWISH. In section 5 we describe four applications of the current system. We conclude with future work and conclusions.
2 Related work
We are not aware of other initiatives that aim at developing a rich web-based development environment for Prolog. We do not compare SWISH with traditional editor or GUI based development environments for Prolog because web-based environments provide new opportunities and pose new challenges. Instead, we discuss three applications that have served as inspiration for SWISH: JSFiddle,999https://jsfiddle.net/ R-Studio101010http://www.rstudio.com/ and IPython Notebook.111111http://ipython.org/notebook.html
As stated, the initial inspiration for SWISH was JSFiddle. Unlike JSFiddle though, Prolog is executed on the server rather than in the browser.
R-Studio  is an interface to the R statistical package. Although not a web application, it is based on the Qt webkit framework and uses web based technology in the background. R-Studio came into the picture when the COMMIT/ project provided a grant for developing SWISH as a toolkit for analysis of relational (SQL) data. The R-studio interface has a similar layout as SWISH, providing a source window, a console and an output plane that typically shows results in tables or charts.
IPython Notebook  allows mixing markdown or HTML text with Python sources. The rendered Notebook shows the text, sources and possible results in the form of numbers, tables or charts.
SWISH embodies most of the ideas behind JSFiddle and R-Studio. Embedding of SWISH in documents is demonstrated in section 5.3. Interactive editing of documents that embed SWISH is discussed in future work (section 6).
Both R-Studio and IPython Notebook work on the basis of authentication (either to the OS or application), after which any command may be executed. SWISH can operate both as a public service granting access to non-intrusive queries and as an authenticated service to run arbitrary queries, for example for maintenance purposes. See section 5.2.
3 The SWISH application
SWISH consists of two parts. The client side, running in a browser, is implemented as a series of jQuery plugins, using Bootstrap for styling and RequireJS121212http://requirejs.org/ for package management. The server side is completely implemented in SWI-Prolog . It builds on top of the SWI-Prolog HTTP server libraries, the Pengines library and the IDE support libraries that provide data for auto completion, documentation and highlighting.
In the following sections we describe SWISH in terms of interface components, where we discuss the requirements, the user aspects, the client code and supporting server functionality for each component. First, we provide a screendump that illustrates the main components in figure 1.
3.1 The code editor
A proper editor is the most important component of a usable programming environment. The editor must support the language, including syntax highlighting, auto indentation, code completion based on templates and already existing code and highlighting of errors and warning from the compiler. The editor is used both for editing the source code and editing queries.
Prolog is a difficult language to support in code editors due to the lack of reserved keywords, e.g., the word if in C starts an if-statement if not embedded in comment or a string, but the word is in Prolog can refer to the built-in predicate is/2, but also some predicate with a different arity, just a constant, etc. Another example is X-Y which can both be an arithmetic expression or a pair as used with e.g., keysort/2. Next to the lack of keywords the ability to extend the syntax using new operators complicates the implementation of syntax support while editing. SWI-Prolog’s built-in Emacs oriented editor resolves this problem by closely integrating Prolog with the editor. While typing, the current term (clause or directive) is parsed and analysed in the context of the current file and the file’s imports after each keystroke. If the term has valid syntax, all tokens are coloured according to their syntactic role as well their relation to the remainder of the program. For example, a call to a non-existing predicate is coloured red, a call to a built-in or imported predicate is blue and a call to a locally defined predicate is black. The libraries that implement this analysis have been decoupled from the built-in editor, both to support source colouring for the SWI-Prolog documentation system PlDoc  and ProDT131313http://prodevtools.sourceforge.net, these libraries are not yet used by ProDT.
A CodeMirror hover plugin is used to show basic information about tokens if the pointer hovers over it. For goals, this includes where the goal is defined (ISO, SWI-Prolog built-in, a library, locally) and the documentation summary information if available. This information is requested from the server.
A CodeMirror template plugin is configured from templates (e.g., atom_length(+Atom, -Length)) extracted from the SWI-Prolog manual and PlDoc documentation of imported libraries. This plugin shows a menu of applicable predicates with their templates on Control-Space.
Finally, if the user uses the Run! button to execute a query, the program is compiled. If the compiler generates errors or warnings, these are inserted as notes in the source code.
3.2 Source code and query management
As JSFiddle formed the initial inspiration for SWISH, SWISH has a facility to save the program. The current version of SWISH explicitly targets the cooperative development of Prolog programs and queries related to a dataset (see section 5.2). This triggered the implementation of a more organised storage facility. The server-side storage module is implemented in Prolog and inspired by GIT. Each file is versioned independently rather than maintaining the version of a hierarchy of files. Files can be referenced by content using their GIT compatible SHA1 hash or by name. The name can be considered a version head and refers to the latest version with that name. The file save and load interface provides the following operations:
Saving a file anonymously, which produces a randomly generated URL similar to JSFiddle.
Saving a file by name.
Saving a new version. The interface shows the available versions and the modifications.
Forking a file under a new name. The history remains linked to the original.
Prolog source files can include other sources on the same server using :- include(filename)., including the latest version or :- include(hash). to include a specific version.
Prolog source files can embed example queries using structured
comments, where each sequence from
?- to the matching full stop
token is added to the Examples menu of the query panel (see
figure 6). The comment below illustrates a call to append/3 embedded
in the source window.
/** ¡examples¿ ?- append([one], [two,three], List). */ \@endparenv
3.3 The query editor
The query editor is based on the same jQuery plugin that realises the code editor and thus profits from the syntax highlighting, template insertion and hovering plugins. In addition, it provides three popup menus:
This menu is filled from the structured comments described above. The examples menu is shown in figure 6.
This menu provides earlier executed queries.
This menu embeds an existing query in a meta-call to alter the result. Currently provided operations are Aggregate (count all), Order by, Distinct, Limit, Time and Debug (trace). Figure 3 shows how the menu is used to count the solutions of a goal.
3.4 Running a query: runners in the answer pane
The answer pane is a placeholder for runners, where each runner represents a query. The answer pane provides a menu for operations on all runners inside it. Provided actions are Collapse all, Expand all, Stop all and Clear. The query may be completed, running or waiting for user input. SWISH can manage multiple active queries at the same time, up to an application defined maximum (default 3).
Each runner provides its own set of commands to control the specific query. During execution a runner provides an Abort button. After query evaluation completes with an answer and more answers may be available the runner allows for asking the next 1, 10, 100 or 1,000 results or to Stop the query. In addition, the runner shows a text input field when the application wants to read input and may show debugger interaction buttons if the tracer is being used (see section 3.4.3).
A runner can render answers in two modes, the classical Prolog mode or as a table, similar to what many database interfaces provide. The ‘table’ mode is particularly appealing for querying datasets (see figure 3), while the former is more suitable for rendering small amounts of complex answers such as the chessboard position in figure 1. By default, Prolog terms are rendered as structured HTML objects, where the rendered text is the same as Prolog’s writeq/1 predicate.
The server can provide rendering libraries that render Prolog terms using dedicated HTML. In figure 1, the ‘chess’ renderer is loaded due to the :- use_rendering(chess) directive. The ‘chess’ renderer translates a list of length holding integers in the range as a chessboard with queens. In addition to the chess rendering library, SWISH provides rendering libraries for sudoku puzzles, parse trees and tables. The ClioPatria version adds a renderer for RDF resources that renders the resource more compactly and provides a hyperlink for obtaining details. If a term can be rendered in multiple ways, the interface provides a hover menu to select between the alternatives. Figure 4 illustrates this functionality. The render facility is similar to the Prolog portray/1 hook that allows changing the result printed for terms with a specific shape. However, it can exploit the full potential of HTML (or SVG) and the interface allow for switching the selected rendering.
A rendering library is a module that must define a non-terminal (grammar rule) term_rendering//3, calling html//1151515http://www.swi-prolog.org/pldoc/doc_for?object=html/3 to produce HTML from the Prolog input term, a list of variable bindings (Name = Variable) and user provided options. In the current version, new rendering modules must be loaded into the SWISH server and cannot be created by the SWISH user.
3.4.1 Server side execution of the query
Server-side execution of a query is supported by the Pengines  library. The Pengines library allows for creating a Prolog engine represented by a Prolog thread. Optionally, the pengine is handed a Prolog program that is loaded into the pengine’s workspace (program space). The workspace is a temporary module that is disposed of after the pengine terminates. The pengine may be asked questions through HTTP queries, similar to a traditional Prolog user interacting with Prolog running in a terminal.161616https://www.youtube.com/watch?v=G_eYTctGZw8
If the SWISH user hits the Run! button, the content of the source pane is used to create a new pengine. Subsequently, the content of the query pane is sent as the one and only query that will be executed by the pengine.171717Pengines can execute multiple queries. We do not use this facility because a fresh pengine starts in a predictable state (standard operators, empty dynamic database). Before execution, the query is verified to be safe, unless sandboxing is disabled (see section 5.2). The sandbox component is discussed below.
The pengine’s default working module may be pre-loaded with code. SWISH uses this facility to redefine the Prolog I/O predicates such as read/1, write/1, format/1,2,3, etc. The ClioPatria version (section 5.2) also preloads the RDF libraries, so users can run queries on the RDF database without explicitly importing the required libraries.
3.4.2 Sandboxing queries
A Prolog environment contains global state in the form of loaded modules, defined operators, dynamic predicates, etc. Prolog exposes a rich and potentially dangerous interface to the operating system. For an anonymous services, we want each query to start in a well defined state and we must ensure that execution of the query does not make unwanted changes to the hosting computer or leaks sensitive information.
Both for education purposes and data analysis one can write meaningful programs without making permanent changes to the server or the server’s filesystem. That is where the sandbox library comes in. The sandbox library is active while loading the source, where it refuses to add clauses to other modules than the pengine’s workspace and where it only accepts a restricted set of directives, also aimed at keeping all changes local to the workspace. Prior to execution, the sandbox unfolds the query and compares all reachable goals with a whitelist. The whitelist contains all side-effect free built-in Prolog predicates, safe meta-predicates (e.g., findall/3) and allows for using the dynamic database, provided that the head of the affected predicate is not module-qualified (and thus the referenced predicate lives in the temporary program space of the Pengine) and the body is safe. It does not allow for cross-module calls (Module:Goal) to private predicates and does not provide access to object-enumeration predicates such as current_atom/1, current_predicate/1, etc., both to avoid leaking sensitive information.
The sandbox test fails under one of these conditions:
It discovers a (meta-) goal for which it cannot deduce the called code. The traditional example is read(X), call(X). If such a goal is encountered, it signals an instantiation error, together with a trace that explains how the insufficiently instantiated goal can be reached. Note that it can deal with normal high-order predicates if the meta-argument is specified. For example, the following goal is accepted as safe.
?- maplist(plus(1), [1,2,3]) \@endparenv
It discovers a goal that is not whitelisted. In this case it signals a permission error, again accompanied with a trace that explains how the goal can be reached. Note that pure Prolog predicates are unfolded, also if it concerns predicates from the libraries or belonging to the set of built in predicates.
It discovers a cross-module (M:Goal) call to a predicate that is not public. Normally, SWI-Prolog, in the tradition of Quintus Prolog, allows for this. Allowing it in SWISH would imply that no data can be kept secret. With this limitation, libraries can keep data in local dynamic predicates that remain invisible to non-authorised users.
The SWISH debugger is based on the traditional 4-port debugging model for Prolog. Figure 5 shows the tracer in action on sublist/2 from the Lists example source. The debugger was triggered by a break-point on line 10 set by clicking on the line-number in the code editor. The debugging interaction is deliberately kept simple and similar to traditional programming environments. A retry button is added to the commonly seen ‘step into’, ‘step over’ and ‘step out’ for highlighting the unique feature of Prolog to re-evaluate a goal.
The server code is basically non-portable. Many of the required libraries and features are shared with at least one other Prolog implementation, but none is capable to support the full range. Below we summarise the main problems.
The scale of the involved Prolog libraries demands for a closely compatible Prolog module system. Probably only SICStus and YAP can be used without significant rewrites.
The HTTP server libraries are heavily based on C code that interacts with the SWI-Prolog foreign language interface to Prolog streams. YAP has copied the low-level libraries and is capable to run (an old version of) these libraries.
The Pengines library depends on the HTTP library and the multi-thread interface. The SWI-Prolog thread API is also provided by YAP and XSB.
The sandbox library (section 3.4.2) assumes that whitelisted predicates are indeed safe. This requires robust handling of invalid calls and resource overflows. Few Prolog systems can satisfy this requirement. SICStus Prolog would be a candidate, but SICStus does not support multi-threading.
The semantic syntax highlighting depends on detailed source layout information provided by read_term/3. SWI-Prolog’s support for term layout is an extended version of the Quintus Prolog term layout functionality.
Significant parts of the code rely on SWI-Prolog version 7 extensions, notably the dict and string types that facilitate a natural mapping between Prolog and JSON data.
From the above list it should be clear that a fully functional port of SWISH to another Prolog system is not immediately feasible. YAP probably comes closest but still requires a significant amount of work.
There is a more realistic scenario though. In this setup, SWI-Prolog provides the web interface and most of the development tools and another language, not even necessarily Prolog, provides the query solving. The interface between the two can be based on interprocess communication or, if the target system is robust, safe and capable of supporting threads, by linking the target system into the process and using the C interface for communication.
In this section we describe and evaluate four publicly available SWISH applications. All these services are regularly updated to run the latest version of SWISH and SWI-Prolog.
SWISH181818http://swish.swi-prolog.org runs a plain publicly accessible copy of SWISH that allows running sandboxed (see section 3.4.2) Prolog programs. The server has collected 10,800 programs between September 29, 2014 and June 2, 2015. Over the month May 2015, it has executed 258,809 Prolog queries. The web site is regularly used by users of the ##prolog IRC channel to discuss programming solutions and is in active use for education.191919Steve Matuszek, UMBC (via e-mail: “Thank you very much for this fantastic resource! I used it while teaching Prolog this semester, and it really helped tighten the loop for my students. We spent zero time on tool installation and other overhead, and all the time on understanding the concepts. I even had them turn their assignments in via SWISH, with their test queries in the examples block.”
ClioPatria is a semantic web (RDF) framework for SWI-Prolog. It consists of an RDF triple store, a SPARQL server and a web frontend to manage the server and explore the data in the RDF store. ClioPatria can be extended using cpacks (ClioPatria pack or plugin). SWISH is available as a ClioPatria cpack202020http://cliopatria.swi-prolog.org/packs/swish and makes the Prolog shell available for querying as well as maintenance tasks. Without login, user can run side-effect free queries over the RDF data stored in ClioPatria’s RDF database. After login with administrative rights, the sandbox limitations are lifted and the Prolog shell can be used to perform maintenance tasks on the RDF data such as data transformation, cleanup, etc., as well as program maintenance tasks such as reloading modified source files.
SWISH has been used in the Talk Of Europe creative camp212121http://www.talkofeurope.eu/ to explore data on the speeches in the European parliament.222222http://purl.org/linkedpolitics Although still immature, users appreciated the ability to define more efficient and expressive queries than provided by the SPARQL query interface. Above all, the ability to save and share programs that perform interesting tasks on the data was frequently used, in particular to seek help fixing queries.
5.3 Learn Prolog Now!
Learn Prolog Now!232323http://www.learnprolognow.org is an
online version of a Prolog book by Patrick Blackburn, Johan Bos, and
Kristina Striegnitz . We established a proof of
concept that embeds SWISH in the online course
material.242424http://lpn.swi-prolog.org It is realised as a
Prolog hosted proxy that fetches the pages from the main site
and serves the enhanced pages to the user. The proxy identifies and
classifies the code fragments in terms of ‘source code’ ‘queries’ and
dependencies. Next, it adds a button to the source fragments that, when
pressed, replaces the HTML
<pre> element with in
running SWISH filled with the source while the example queries are added
to the Examples menu (figure 6). The queries are executed
by http://swish.swi-prolog.org. Program and queries are
transferred using the following HTTP parameters: code (the
source code), background (source code that is loaded into the
pengine but not visible in the editor), examples (queries that
appear in the Examples menu) and q (the initial query).
The proxy server served 19,700 pages during May 2015.
5.4 cplint on SWISH
cplint on SWISH252525http://cplint.lamping.unife.it/ is a web application based on SWISH for reasoning with probabilistic logic programs under the distribution semantics. The Prolog source window is used to write a logic program with annotated disjunction. A query in the form of a ground atom is answered by returning its probability of being true in the program. The computation of the probability is done with the cplint system  in the server using Pengines. The input program is translated into an internal representation using source to source transformation.
Prob which will hold the probability and will be shown to the user in the answer pane.
5.5 TRILL on SWISH
TRILL on SWISH262626http://trill.lamping.unife.it/ is a probabilistic OWL reasoner that reuses SWISH. As SWISH for ClioPatria, described in section 5.2, it is a ClioPatria cpack. The Prolog source window is replaced by an RDF/XML editor window that can be used to upload an OWL ontology while the query editor can be used to pose Prolog queries against the OWL ontology. The probability of queries is computed using TRILL , a reasoner in Prolog that adopts the distribution semantics for probabilistic description logics.
6 Future work
Although definitely usable in its current state, SWISH is work in progress. We are confident that the basic component selection and organisation of the server and client code are stable. More work is needed to improve the current system. Notably the semantic highlighting is not yet perfect and often fails to degrade gradually if the server side annotation does not match the client tokens perfectly. The Pengine’s sandbox protection is often too restrictive, while several security flaws have been reported and fixed already. It is, and probably always will be, advised to run public SWISH-enabled services in an operating system sandbox. The current server suffers from memory leaks and stability problems. Although the situation has improved significantly, the main demo server needs to be restarted about once a week.272727A restart of the server has only small consequences to active users. Open queries are killed. The source code mirror is lost, but automatically recovered if the client asks for a new set of semantically enriched tokens.
We foresee several extensions to SWISH that will improve current applications and enable new opportunities for deploying SWISH.
Multi-document editing can enhance the sandboxed SWISH application by providing input and output documents. Compare this to TRILL (section 5.5) using an RDF/XML document as input.
We plan to provide a markdown-based format specifically for writing tutorials and well as dataset analysis documents. The first will look like the Learn Prolog Now! example discussed in section 5.3. For the second, we envision a document with embedded code and query fragments, where the query fragments produce tables or charts. This is similar to IPython Notebook.
Turn http://swish.swi-prolog.org into a reliable and scalable resource. Examine the possibility for schools to instantiate a private version that is preloaded with course material and assignments.
The development of SWISH was supported by the Dutch national program COMMIT/.
-  Patrick Blackburn, Johan Bos, and Kristina Striegnitz. Learn prolog now!, volume 7. College Publications, 2006.
-  Christopher Gandrud. Reproducible Research with R and R Studio. CRC Press, 2013.
-  Torbjörn Lager and Jan Wielemaker. Pengines: Web logic programming made easy. TPLP, 14(4-5):539–552, 2014.
-  Fabrizio Riguzzi and Terrance Swift. Well-definedness and efficient inference for probabilistic logic programming under the distribution semantics. Theory Pract. Log. Program., 13(Special Issue 02 - 25th Annual GULP Conference):279–302, March 2013.
-  Cyrille Rossant. Learning IPython for interactive computing and data visualization. Packt Publishing Ltd, 2013.
-  Jan Wielemaker and Anjo Anjewierden. PlDoc: Wiki style literate programming for Prolog. In Patricia Hill and Wim Vanhoof, editors, Proceedings of the 17th Workshop on Logic-Based methods in Programming Environments, pages 16–30, 2007.
-  Jan Wielemaker, Zhisheng Huang, and Lourens van der Meij. Swi-prolog and the web. TPLP, 8(3):363–392, 2008.
-  Riccardo Zese, Elena Bellodi, Evelina Lamma, Fabrizio Riguzzi, and Fabiano Aguiari. Semantics and inference for probabilistic description logics. In Uncertainty Reasoning for the Semantic Web III, volume 8816 of LNCS, pages 79–99. Springer, 2014.