:- module bug_x64_typeclass.
:- interface.
:- import_module io.

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

:- implementation.

:- import_module string, int, type_desc, require.



:- pred debugstr(string::in, T::in, io::di, io::uo) is det.
debugstr(Msg, Data, !IO) :-
  io__stderr_stream(E, !IO),
  io__write_string(E, Msg, !IO),
  io__write(E, Data, !IO),
  io__nl(E, !IO).


:- type h(A, B) ---> h(val::float, a::A, b::B).

:- instance stackable(h(OCC, OC), float, string) where [
     pred(recombine/1) is myrecombine
   ].



:- pred myrecombine(h(OCC, OC)::in) is semidet
        <= (stackable(h(OCC, OC), float, string)).
myrecombine(H1) :-
  trace[io(!IO)] debugstr("Recombining: ", type_of(H1), !IO),
  (
  if type_of(H1) \= type_of(h0)
  then error("type screwed up")
  else trace[io(!IO)]debugstr("The type is correct: ", type_of(h0), !IO)
  ),
  fail.

:- func h0 = h(string, string).
h0 = h(10.0, "a-is-string", "b-is-string").


main(!IO) :-
  some[!S] (
  !:S = new(10),
  insert_prune(h0, !S),
  debugstr("Got: ", !.S, !IO)
  ).



:- typeclass stackable(T, Score, K)
      <= ( (T->Score), (T->K)) where [
     pred recombine(T::in) is semidet
   ].

:- type stack(T, Score, K). % <= stackable(T, Score, K).

:- func new(int) = stack(T, Score, K).  % create a new stack with stacklimit N

:- pred insert_prune(T::in, stack(T, S, K)::in, stack(T, S, K)::out) is det
     <= stackable(T, S, K).


:- type stack(T, Score, K) ---> 
          blank( sl::int, pl::int).
          /*
        ; stack(
            worst :: Score,
            elems :: map(K, T),
            stack_limit :: int,
            prune_limit :: int,
            cnt :: int
          ).
          */

new(StackLimit) = blank(StackLimit, StackLimit*2).


insert_prune(H, InStack, OutStack):-
  trace[io(!IO)]debugstr("insprune calls recombine: ", type_of(H), !IO),
  (
  if recombine(H)
  then OutStack = blank(InStack^sl*2, 0)
  else OutStack = InStack
  ).



