% typecheck.pl
% Some skeleton starter code for Assigment 5
% Author: Frank Pfenning
% September 2006

% Change precedence to
% 1200 xfx :- :
% 1050 xfy ->
% 1000 xfy ,
:- op(1200, xfx, ':').
:- discontiguous([(:)/2]).

% check_all
% Retrieve and check the signature for well-formedness
% then type-check each predicate with a type declaration.
check_all :-
	check_sig(Preds),
	check_prog(Preds).

% check_sig(-Preds)
% Check signature and retrive list of Pred/Arity pairs
check_sig(Preds) :-
	findall((C : V), clause((C : V), true), Decls),
	check_decls(Decls),
	collect_preds(Decls,Preds).
check_decls([]).
check_decls([(C : V)|Decls]) :-
	format("Decl ~p : ~p.\n", [C,V]),
	atom(C),
	check_class(V),
	check_decls(Decls).

% collect_preds(+Decls, -Pred)
% Collect Pred/Arity pairs from Decls
collect_preds([], []).
collect_preds([(Pred : Taus -> o)|Decls], [Pred/Arity|Preds]) :- !,
	length(Taus, Arity),
	collect_preds(Decls, Preds).
collect_preds([_|Decls], Preds) :-
	collect_preds(Decls, Preds).

% check_class(Classifier)
% Check that classifer is well-formed
%
% Provides an example how reification may be used
% to represent types as explicit terms
check_class((Ks -> type)) :- !,
	check_kinds(Ks).
check_class((Taus -> o)) :- !,
	reify_terms(Taus, Ts, 1, N2),
	quantify_upto(1, N2, pred(Ts), PolyT),
	check_poly(PolyT, []).
check_class((Sigmas -> Tau)) :- !,
	reify_term(Tau, T, 1, N2),
	reify_terms(Sigmas, Ss, N2, N3),
	quantify_upto(1, N3, arrow(Ss, T), PolyT),
	check_poly(PolyT, []).
