
:- module bug271.

:- interface.

:- import_module io.

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

:- implementation.

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

:- type a_or_b
    --->    a
    ;       b.

main(!IO) :-
    get_a_or_b(AB),
    (
        AB = a,
        obj_to_num(obj, X),
        S = to_string(X)
    ;
        AB = b,
        obj_to_num(obj, X),
        S = to_string(X)
    ),
    format("%s\n", [s(S)], !IO).

:- pred get_a_or_b(a_or_b::out) is det.

:- typeclass literal(X) where [
    func literal_type(X) = literal_type
].

:- typeclass num(X) where [
    func to_string(X) = string
].

:- some [Y] (pred obj_to_num(object(X)::in, Y::out) is det => num(Y)) <= literal(X).

% We need a clause so that Y gets a type assignment.
obj_to_num(_, 15).

:- type object(L) --->
    object(L).
:- type literal ---> literal.
:- type literal_type ---> literal_type.
:- func obj = object(literal).

:- instance literal(literal) where [
    (literal_type(literal) = literal_type)
].

:- instance num(int) where [
    (to_string(X) = string(X))
].

