%---------------------------------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%---------------------------------------------------------------------------%

:- module x.
:- interface.

:- import_module io.

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

%---------------------------------------------------------------------------%

:- implementation.

:- type animal
    --->    ant         % 0
    ;       bat         % 1
    ;       cat         % 2
    ;       dog         % 3
    ;       eel         % 4
    ;       fox         % 5
    ;       gnu         % 6
    ;       hog         % 7
    ;       ibis        % 8
    ;       jay         % 9
    ;       kea         % 10
    ;       lark        % 11
    ;       moa         % 12
    ;       newt        % 13
    ;       owl         % 14
    ;       pug.        % 15

:- type struct1
    --->    structctor1(
                animal, animal,                         % word 0
                int,                                    % word 1
                string,                                 % word 2
                animal, animal, animal, animal          % word 3
            ).

:- type notag_animal
    --->    notag_animal(animal).

:- type struct2
    --->    structctor2(
                notag_animal, animal,                   % word 0
                int,                                    % word 1
                string,                                 % word 2
                notag_animal, animal, animal, animal    % word 3
            ).

%---------------------------------------------------------------------------%

main(!IO) :-
    Dynamic1 = structctor1(ani(pug), ani(owl), 1000, "string",
        ani(newt), ani(moa), lark, jay),
    write_struct1(Dynamic1, !IO),
    io.nl(!IO),
    Dynamic2 = structctor2(notag_animal(ani(pug)), ani(owl), 1000, "string",
        notag_animal(ani(newt)), ani(moa), lark, jay),
    write_struct2(Dynamic2, !IO),
    io.nl(!IO).

:- func ani(animal) = animal.
:- pragma no_inline(ani/1).

ani(X) = X.

:- pred write_struct1(struct1::in, io::di, io::uo) is det.
:- pragma no_inline(write_struct1/3).

write_struct1(structctor1(A, B, I, S, C, D, E, F), !IO) :-
    write_animal(A, !IO), write_string(", ", !IO),
    write_animal(B, !IO), write_string(", ", !IO),
    write_int(I, !IO),    write_string(", ", !IO),
    write_string(S, !IO), write_string(", ", !IO),
    write_animal(C, !IO), write_string(", ", !IO),
    write_animal(D, !IO), write_string(", ", !IO),
    write_animal(E, !IO), write_string(", ", !IO),
    write_animal(F, !IO).

:- pred write_struct2(struct2::in, io::di, io::uo) is det.
:- pragma no_inline(write_struct2/3).

write_struct2(structctor2(A, B, I, S, C, D, E, F), !IO) :-
    write_notag_animal(A, !IO), write_string(", ", !IO),
    write_animal(B, !IO), write_string(", ", !IO),
    write_int(I, !IO),    write_string(", ", !IO),
    write_string(S, !IO), write_string(", ", !IO),
    write_notag_animal(C, !IO), write_string(", ", !IO),
    write_animal(D, !IO), write_string(", ", !IO),
    write_animal(E, !IO), write_string(", ", !IO),
    write_animal(F, !IO).

:- pred write_animal(animal::in, io::di, io::uo) is det.

write_animal(Animal, !IO) :-
    write(Animal, !IO).

:- pred write_notag_animal(notag_animal::in, io::di, io::uo) is det.

write_notag_animal(NotagAnimal, !IO) :-
    NotagAnimal = notag_animal(Animal),
    write(Animal, !IO).
