Skip to content

guregu/pengine

Repository files navigation

pengine GoDoc

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!

Usage

This library supports both the JSON and Prolog format APIs. Additionally, an RPC predicate for ichiban/prolog is provided.

Configuration

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",
}

JSON API

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.

Prolog API

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.

Warning about Unicode atoms

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)
               ]).

RPC for ichiban/prolog

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 ...

Tests

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.

Other languages

Check out these pengines clients for other languages.

Thanks

  • 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.

License

BSD 2-clause.