%---------------------------------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%---------------------------------------------------------------------------%
%
% Test the mdb `dice' command.
% Buggy merge sort taken from Lee Naish's probabalistic declarative debugging
% paper.
%
%---------------------------------------------------------------------------%
%
% The .exp file is for asm_fast.gc bootchecks.
% The .exp2 file is for XXX.
% The .exp3 file is for XXX.
%
%---------------------------------------------------------------------------%

:- module dice.

:- interface.

:- import_module io.

:- pred main(io::di, io::uo) is det.

:- implementation.

:- import_module int.
:- import_module string.
:- import_module list.
:- import_module exception.

main(!IO) :-
    io.command_line_arguments(Args, !IO),
    ( if list.map(string.to_int, Args, Ints) then
        merge_sort(Ints, Sorted),
        io.write(Sorted, !IO),
        io.nl(!IO)
    else
        io.write_string("usage error\n", !IO)
    ).

:- pred merge_sort(list(int)::in, list(int)::out) is det.

merge_sort(Us, Ss) :-
    N = list.length(Us),
    msort_n(N, Us, Ss, _).

:- pred msort_n(int::in, list(int)::in, list(int)::out, list(int)::out) is det.

msort_n(N, Unsorted, SortedPart, Rest) :-
    ( if N =< 0 then
        SortedPart = [],
        Rest = Unsorted
    else if N = 1 then
        (
            Unsorted = [U | Us],
            SortedPart = [U],
            Rest = Us
        ;
            Unsorted = [],
            throw("Unsorted = [] and N = 0")
        )
    else
        N1 = N // 2,
        dice.msort_n(N1, Unsorted, Ss1, Us2),
        N2 = N - N1,
        msort_n(N2, Us2, Ss2, Rest),
        dice.merge(Ss1, Ss2, SortedPart)
    ).

:- pred merge(list(int)::in, list(int)::in, list(int)::out) is det.

merge([], [], []).
merge([S | Ss], [], [S | Ss]).
merge([], [S | Ss], [S | Ss]).
merge([A | As], [B | Bs], [C | Cs]) :-
    ( if A =< B then
        dice.merge(As, [B | Bs], Cs),
        C = A
    else
        dice.merge(As, [B | Bs], Cs), % BUG
        C = B
    ).
