import "github.com/guregu/pengine"
Pengines: Prolog Engines client for Go. Pengines's motto is "Web Logic Programming Made Easy". This library lets you query SWI-Prolog from Go and from ichiban/prolog, a Prolog interpreter written in Go.
Development Status: beta. Feedback and contributions welcome!
This library supports both the JSON and Prolog format APIs. Additionally, an RPC predicate for ichiban/prolog is provided.
client := pengine.Client{
// URL of the pengines server, required.
URL: "http://localhost:4242/pengine",
// Application name, optional.
Application: "pengines_sandbox",
// Chunk is the number of query results to accumulate in one response. 1 by default.
Chunk: 10,
// SourceText is Prolog source code to load (optional, currently only supported for the JSON format).
SourceText: "awesome(prolog).\n",
// SourceURL specifies a URL of Prolog source for the pengine to load (optional).
SourceURL: "https://example.com/script.pl",
}
client.Ask
returns an Answers[Solutions]
iterator, but you can use the generic pengine.Ask[T]
function to use your own types.
answers, err := client.Ask(ctx, "between(1,6,X)")
if err != nil {
panic(err)
}
var got []json.Number
for as.Next() {
cur := as.Current()
x := cur["X"]
got = append(got, x.Number)
}
// got = {"1", "2", "3", ...}
if err := answers.Error(); err != nil {
panic(err)
}
You can also use client.Create
to create a pengine and Ask
it later. If you need to stop a query early or destroy a pengine whose automatic destruction was disabled, you can call client.Close
.
client.AskProlog
returns ichiban/prolog/engine.Term
objects. This uses the ichiban/prolog parser to handle results in the Prolog format. Use this for the most accurate representation of Prolog terms, but be aware that the parser does not support all of SWI's bells and whistles.
You can also call pengine.Term.Prolog()
to get Prolog terms from the JSON results, but they might be lossy in terms of Prolog typing.
SWI-Prolog's defaults around Unicode cause errors for our Prolog parser at the moment, so we need to tweak the configuration.
- We can't handle SWI's
\uXXXX
Unicode escapes.- This can interfere with unification of query results and cause unexpected "no solutions found" errors.
Luckily, Pengines makes it easy for us to customize the result formatter and fix this. Just define a pengines:write_result/3
hook for the prolog
format on your Pengines server.
Here's an example of a working Pengines configuration:
pengines:write_result(prolog, Event, _) :-
format('Content-type: text/x-prolog; charset=UTF-8~n~n'),
write_term(Event,
[ quoted(true),
quote_non_ascii(true), % 👈
character_escapes_unicode(false), % 👈
ignore_ops(true),
fullstop(true),
blobs(portray),
portray_goal(pengines:portray_blob),
nl(true)
]).
You can call remote pengines from ichiban/prolog, a Go Prolog, as well.
pengine_rpc/3
mostly works like its SWI-Prolog counterpart.
Not all the options are implemented yet, but it seems to work OK!
interpreter.Register3("pengine_rpc", pengine.RPC)
:- pengine_rpc('http://localhost:4242/pengine', between(1,50,X), [chunk(10)]), write(X), nl.
% 1 2 3 4 ...
Currently the tests are rather manual:
% from swipl
consult(example_server).
# from OS terminal
go test -v
Change the pengines server URL used by the tests with the --pengines-server
command line flag.
Check out these pengines clients for other languages.
- Programming against SWISH is an up-to-date list of clients.
- Erlang: erl_pengine
- Java: JavaPengine
- Javascript: pengines.js
- Python: PythonPengines
- Ruby: RubyPengines
- Torbjörn Lager, Jan Wielemaker, and everyone else who has contributed to SWI-Prolog and Pengines.
- @ian-andrich for the Python implementation, which was a handy reference for making this.
- @ichiban for the awesome Prolog interpreter in Go.
- Markus Triska for the wonderful tutorial series The Power of Prolog, which started me on my logic programming journey.
BSD 2-clause.