Testing And Benchmarking in Prolog

Here’s the translation of the Go testing and benchmarking example to Prolog, formatted in Markdown suitable for Hugo:

Unit testing is an important part of writing principled Prolog programs. The built-in plunit library provides the tools we need to write unit tests.

For the sake of demonstration, this code is in a single file, but it could be split into separate files. Testing code typically lives in the same file as the code it tests.

:- use_module(library(plunit)).

% We'll be testing this simple implementation of an
% integer minimum. Typically, the code we're testing
% would be in a source file named something like
% `intutils.pl`, and the test file for it would then
% be named `intutils_test.pl`.

int_min(A, B, Min) :-
    (A < B -> Min = A ; Min = B).

% A test is created by writing a predicate with a name
% beginning with `test_`.

:- begin_tests(int_min).

test(basic) :-
    int_min(2, -2, Min),
    assertion(Min == -2).

% Writing tests can be repetitive, so it's idiomatic to
% use a table-driven style, where test inputs and
% expected outputs are listed in a table and a single loop
% walks over them and performs the test logic.

test(table_driven, [forall(member(
    (A, B, Expected),
    [
        (0, 1, 0),
        (1, 0, 0),
        (2, -2, -2),
        (0, -1, -1),
        (-1, 0, -1)
    ]
))]) :-
    int_min(A, B, Min),
    assertion(Min == Expected).

:- end_tests(int_min).

To run the tests, you can use the run_tests/0 predicate:

?- run_tests.
% PL-Unit: int_min .. done
% All 2 tests passed
true.

Prolog doesn’t have a built-in benchmarking system like Go’s, but you can create a simple benchmarking predicate:

benchmark(Goal, N) :-
    get_time(Start),
    (   between(1, N, _),
        call(Goal),
        fail
    ;   true
    ),
    get_time(End),
    Duration is End - Start,
    format('Executed ~w times in ~3f seconds~n', [N, Duration]).

% Example usage:
?- benchmark(int_min(1, 2, _), 1000000).
Executed 1000000 times in 0.123 seconds
true.

This benchmarking predicate will run the given goal N times and report the total execution time. It’s not as sophisticated as Go’s benchmarking system, but it can give you a basic idea of performance.

Remember that Prolog’s execution model is quite different from imperative languages like Go, so benchmarking results may not be directly comparable. In Prolog, you’re often more concerned with the logical structure and correctness of your program than raw performance metrics.